Redis 概念以及底層資料結構

2021-09-24 03:08:10 字數 3482 閱讀 2170

remote dictionary server(redis) 是乙個由salvatoresanfilippo寫的key-value儲存系統。

redis是乙個開源的使用ansi c語言編寫、遵守bsd協議、支援網路、可基於記憶體亦可持久化的日誌型、key-value資料庫,並提供多種語言的api。

它通常被稱為資料結構伺服器,因為值(value)可以是字串(string), 雜湊(map), 列表(list), 集合(sets) 和有序集合(sorted sets)等型別。

redis 是完全開源免費的,遵守bsd協議,是乙個高效能的key-value資料庫。

redis 與其他 key - value 快取產品有以下三個特點:

效能極高 – redis能讀的速度是110000次/s,寫的速度是81000次/s 。

豐富的資料型別 – redis支援 strings, lists, hashes, sets 及 ordered sets 資料型別操作。

原子 – redis的所有操作都是原子性的,同時redis還支援對幾個操作全並後的原子性執行。

豐富的特性 – redis 還支援 publish/subscribe, 佇列,key 過期等等特性。

redis> set message "hello redis"
其中的key是message,是乙個包含了字串"message"的物件。而value是乙個包含了"hello redis"的物件。 redis共有五種物件的型別,分別是:

型別常量

物件的名稱

redis_string

字串物件

redis_list

列表物件

redis_hash

雜湊物件

redis_set

集合物件

redis_zset

有序集合物件

redis中的乙個物件的結構體表示如下:

typedef struct redisobject  robj;
type表示了該物件的物件型別,即上面五個中的乙個。但為了提高儲存效率與程式執行效率,每種物件的底層資料結構實現都可能不止一種。encoding就表示了物件底層所使用的編碼。

編碼常量

編碼所對應的底層資料結構

redis_encoding_int

long 型別的整數

redis_encoding_embstr

embstr 編碼的簡單動態字串

redis_encoding_raw

簡單動態字串

redis_encoding_ht

字典redis_encoding_linkedlist

雙端鍊錶

redis_encoding_ziplist

壓縮列表

redis_encoding_intset

整數集合

redis_encoding_skiplist

跳躍表和字典

字串物件的編碼可以是int、raw或者embstr 如果乙個字串的內容可以轉換為long,那麼該字串就會被轉換成為long型別,物件的ptr就會指向該long,並且物件型別也用int型別表示。 普通的字串有兩種,embstr和raw。embstr應該是redis 3.0新增的資料結構,在2.8中是沒有的。如果字串物件的長度小於39位元組,就用embstr物件。否則用傳統的raw物件。

#define redis_encoding_embstr_size_limit 44  

robj *createstringobject(char *ptr, size_t len)

embstr的好處有如下幾點:

embstr的建立只需分配一次記憶體,而raw為兩次(一次為sds分配物件,另一次為objet分配物件,embstr省去了第一次)。

相對地,釋放記憶體的次數也由兩次變為一次。

embstr的objet和sds放在一起,更好地利用快取帶來的優勢。

raw和embstr的區別可以用下面兩幅圖所示:

ziplist是一種壓縮鍊錶,它的好處是更能節省記憶體空間,因為它所儲存的內容都是在連續的記憶體區域當中的。當列表物件元素不大,每個元素也不大的時候,就採用ziplist儲存但當資料量過大時就ziplist就不是那麼好用了。因為為了保證他儲存內容在記憶體中的連續性,插入的複雜度是o(n),即每次插入都會重新進行realloc。如下圖所示,物件結構中ptr所指向的就是乙個ziplist整個ziplist只需要malloc一次,它們在記憶體中是一塊連續的區域。

linkedlist是一種雙向鍊錶。它的結構比較簡單,節點中存放pre和next兩個指標,還有節點相關的資訊。當每增加乙個node的時候,就需要重新malloc一塊記憶體。

hashtable的是由dict這個結構來實現的, dict是乙個字典,其中的指標dicht ht[2] 指向了兩個雜湊表

typedef struct dict  dict;  

typedef struct dictht dictht;

dicht[0] 是用於真正存放資料,dicht[1]一般在雜湊表元素過多進行rehash的時候用於中轉資料。 dictht中的table用語真正存放元素了,每個key/value對用乙個dictentry表示,放在dictentry陣列中。

#define intset_enc_int16 (sizeof(int16_t))  

#define intset_enc_int32 (sizeof(int32_t))

#define intset_enc_int64 (sizeof(int64_t))

intset是乙個有序集合,查詢元素的複雜度為o(logn),但插入時不一定為o(logn),因為有可能涉及到公升級操作。比如當集合裡全是int16_t型的整數,這時要插入乙個int32_t,那麼為了維持集合中資料型別的一致,那麼所有的資料都會被轉換成int32_t型別,涉及到記憶體的重新分配,這時插入的複雜度就為o(n)了。 intset不支援降級操作。

/* 

* 跳躍表

*/

typedef struct zskiplist zskiplist;

/* zsets use a specialized version of skiplists */

/* * 跳躍表節點

*/

typedef struct zskiplistnode level;

} zskiplistnode;

head和tail分別指向頭節點和尾節點,然後每個skiplistnode裡面的結構又是分層的(即level陣列) 用圖表示,大概是下面這個樣子:

以上簡單介紹了redis的簡介,特性以及五種物件型別和五種物件型別的底層實現。事實上,redis的高效性和靈活性正是得益於同乙個物件型別採用不同的底層結構,並且在必要的時候對二者進行轉換,還有就是各種底層結構對記憶體的合理利用。

Redis底層資料結構?

福哥口訣法 簡鏈字跳整 壓快壓 sds synamic string 簡單動態字串。支援自動動態擴容的位元組陣列 list 鍊錶 雙端鍊錶。dict 字典。使用雙雜湊表實現的,支援平滑擴容的字典 zskiplist 跳躍表。附加了後向指標的跳躍表 intset 整數集合。用於儲存整數數值集合的自有結...

Redis底層資料結構

redis底層實現的8種資料結構 sds synamic string 支援自動動態擴容的位元組陣列 list 鍊錶 dict 使用雙雜湊表實現的,支援平滑擴容的字典 zskiplist 附加了後向指標的跳躍表 intset 用於儲存整數數值集合的自有結構 ziplist 一種實現上類似於tlv,但...

redis底層資料結構

1.1 string字串 表現形式為 資料結構 sds 簡單的動態字串 使用原因 redis是使用c語言開發的,但在c語言中是沒有字串型別的,只能使用指標或符陣列的形式表示乙個字串,所以在redis設計了一種簡單的動態字串 可以根據不同的資料型別不同的資料結構選擇不同的資料結構 支援的資料型別 字串...