Redis基本結構

 以前看了《Redis設計與實現》這本書,對Redis的認識加深了一些,便作了一些總結,同時也記錄下本身的一些想法。html

 這節先介紹Redis提供的基本結構,主要分爲底層的基本結構和以對象形式包裝的Object結構。redis

1.SDS

 C字符串在redis中主要用於無須對字符串值進行修改的地方,對於須要修改字符串的場景,則使用SDS(簡單動態字符串)。數組

SDS的結構以下示:服務器

file

 其中buff是字符串緩衝區,用於存放字符串,len爲buf數組中已使用字節的數量,free爲buf數組中未使用字節的數量。注意,buff中存放的是二進制數據,使用len屬性來判斷字符串是否結束,保留’\0’符號是爲了兼容部分C函數。數據結構

 同C字符串相比,因爲SDS記錄了相關的使用狀況,於是可以以常數複雜度獲取字符串長度,而且可以杜絕緩衝區溢出。同時,經過使用空間預分配和惰性空間釋放兩種策略,可以減小修改字符串時帶來的內存重分配次數。函數

 所謂空間預分配是指,當對SDS進行修改的時候,而且須要對SDS空間進行擴展的時候,程序不只會爲SDS分配修改所須要的空間,還會爲SDS分配額外的未使用空間。其分配策略是以下定義的:若是對SDS修改後的長度小於1MB,那麼程序分配和len屬性一樣大小的未使用空間;若是對SDS修改後的長度大於等於1MB,那麼程序會分配1MB的未使用空間。經過空間預分配策略,redis能夠減小連續執行字符串增加操做所須要的內存重分配次數。ui

 所謂惰性空間釋放,就是當須要縮短SDS保存的字符串的時候,程序並不當即使用內存從新分配來回收縮短後多出來的字節,而是使用free屬性將這些字節的數量記錄下來,並等未來使用。編碼

 SDS的行爲同Java中的StringBuilder相似。設計

2.list

 list結構是個標準的無環雙向鏈表實現,結構以下:3d

file

 具體過程再也不講解,網上對該結構的講解比較多。

3.dict

 dict結構是個標準的字典實現,使用鏈地址法解決衝突。Dict的結構以下:

file

 其中ht是一個長度爲2的數組,通常狀況下只使用了ht[0],ht[1]用於rehash過程。rehashidx記錄了rehash的過程,-1表示沒有在進行。redis採用漸進式rehash的方式來rehash,防止在數量龐大時致使服務器在一段時間內中止服務。

 漸進式rehash的主要過程爲:爲dict的ht[1]哈希表分配空間,能夠是擴容,也能夠是縮容;將保存在ht[0]中的全部鍵值對從新計算索引值,rehash到ht[1]上;遷移完成後釋放ht[0],將ht[1]設置爲ht[0],並在ht[1]新建立一個空白哈希表,爲下一次rehash作準備。

4.jump List

 跳錶是有序集合的底層實現之一。

 關於跳錶的細節,能夠看下面的介紹

 redis使用跳錶不用紅黑樹的緣由在於:

 在插入、刪除、查找以及迭代輸出有序序列這幾個操做上,跳錶跟紅黑樹的時間複雜度是同樣的,可是在按區間查找數據的操做上,跳錶的效率比紅黑樹更高。

  1. 跳錶較紅黑樹更好實現,意味着可讀性好、不易出錯。

  2. 跳錶更加靈活,能夠經過改變索引結構來平衡執行效率和內存消耗之間的關係

5.intset

 當一個集合只包含整數值元素,而且這個集合的元素數量很少時,redis就會使用整數集合做爲集合的底層實現。下面是intset的結構

file

 其中content用於存儲整數集合的值,length爲content的長度,encoding爲content中存儲的整數的類型,能夠爲int_16,int_32和int_64。

 當須要新增元素到intset裏時,redis會保證元素是有序的。若是content長度不夠或者新增的類型同encoding的類型不一樣,還會觸發intset的升級。升級過程包括從新分配content大小(以新的encoding類型爲準),必要時提高encoding的類型,移動元素的位置,最後修改length屬性。

 注意,intset不支持降級操做,一旦對數組進行了升級,編碼就會一直保持升級後的狀態。

6.zipList

 當一個列表鍵只包含少許列表項,而且每一個列表項要麼就是小整數,要麼就是長度比較短的字符串,那麼就會使用壓縮列表來作列表鍵的底層實現。

 壓縮列表的結構以下:

file

 每一個zipList節點的組成部分以下:

file

每一個節點保存一個字節數據或者一個整數值,其中字節數組和整數值都容許保存不一樣的長度,由encoding屬性決定。previous_entry_length屬性則記錄了前一個節點的長度,使用1個字節或者5個字節來存儲,在新節點加入時可能引發連鎖更新.

7.object

 Redis以對象的形式來存儲鍵值,提供了字符串對象,列表對象,哈希對象,集合對象和有序集合對象5種類型。並使用引用計數來管理對象的回收。

 對象結構的主要屬性包括type,encoding和ptr屬性。

 其中type屬性記錄了對象的類型,這個屬性的值包括:

類型常量 對象的名稱
REDIS_STRING 字符串對象
REDIS_LIST 列表對象
REDIS_HASH 哈希對象
REDIS_SET 集合對象
REDIS_ZSET 有序集合對象

 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 跳躍表和字典
1.REDIS_STRING

 字符串對象的編碼能夠爲INT,EMBSTR或者RAW。當字符串對象保存的是整數,且該整數可以用long來表示,則使用int存儲整數值;當保存的是一個字符串,且長度小於39字節,則使用embstr編碼,大於39字節則使用raw編碼.關於二者的區別,能夠看下面的說明。而embstr要以39個字節來劃分的緣由能夠看這個說明

2.REDIS_LIST

 列表對象的編碼能夠爲ZIPLIST或者LINKEDLIST。

 當列表對象能夠同時知足如下兩個條件時,列表對象使用ziplist編碼:

  1. 列表對象保存的全部字符串元素的長度都小於64字節;

  2. 列表對象保存的元素數量小於512個 若不知足則使用linkedlist編碼,該條件能夠經過配置文件的配置項list-max-ziplist-value和list-max-ziplist-entries進行修改。

3.REDIS_HASH

 哈希對象的編碼能夠爲ZIPLIST或者HASHTABLE

 當哈希對象能夠同時知足如下兩個條件時,哈希對象使用ziplist編碼:

  1. 哈希對象保存的全部鍵值對的鍵和值的字符串當度都小於64字節;

  2. 哈希對象保存的鍵值對數量小於512個  若不知足則使用hashtable編碼,該條件能夠經過配置文件的配置項hash-max-ziplist-value和hash-max-ziplist-entries進行修改。

4.REDIS_SET

 集合對象的編碼能夠爲INTSET或者HASHTABLE

 當集合對象能夠同時知足如下兩個條件時,使用intset編碼:

  1. 集合對象保存的全部元素都是整數值;

  2. 集合對象保存的元素數量不超過512個

 若不知足則使用hashtable編碼,該條件能夠經過配置文件的配置項set-max-intset-entries進行修改。

5.REDIS_ZSET

 有序集合的編碼能夠爲ZIPLIST或者SKIPLIST

 當有序集合對象同時知足如下兩個條件時,使用ziplist

  1. 有序集合保存的元素數量小於128個;

  2. 有序集合保存的全部元素成員的長度都小於64字節;

 若不知足則使用skiplist編碼,該條件能夠經過配置文件的配置項zset-max-ziplist-entries和zset-max-ziplist-values進行修改。

file  我的公衆號:啊駝

相關文章
相關標籤/搜索