本文是《Redis設計與實現》的閱讀筆記。數組
Redis中的字符串使用「簡單動態字符串」(SDS)表示,不管是字符串值仍是鍵底層都採用「簡單動態字符串」。數據結構
free
:未使用空間大小;len
:字符串長度;buf
:以空字符結尾的char數組。爲了減小內存從新分配次數,SDS作出瞭如下優化:函數
len
屬性一樣大小的未使用空間,free
屬性將這些字節的數量記錄起來,並等待未來使用。鏈表是Redis列表鍵實現之一,也是不少其餘功能實現的基礎,鏈表節點定義以下:優化
鏈表的完整結構體定義以下編碼
head
爲表頭指針;tail
爲表尾指針;len
爲鏈表長度計數器;dup
爲函數指針,用於複製鏈表節點所保存的值;free
爲函數指針,用於釋放鏈表節點所保存的值;match
爲函數指針,則用於對比鏈表節點所保存的值和另外一個輸入值是否相等。字典將鍵和值進行關聯,當哈希鍵中的鍵值對數量比較多,或者鍵值對中的元素比較大的時候,採用字典做爲底層實現。字節的數據結構以下設計
哈希表結構dict
中,table
屬性是一個數組,每一個元素都是指向dictEntry
結構的指針,size
屬性記錄了哈希表的大小,sizemask
屬性的值老是等於size-1
,而used
屬性則記錄了哈希表目前已有節點(鍵值對)的數量。3d
字典結構dictType
中有兩個哈希表ht[0]
和ht[1]
,ht[l]
哈希表只會在對 ht[0]
哈希表進行rehash時使用,rehashidx
它記錄了rehash目前的進度。type
屬性是一個指向dictType
結構的指針,dictType
結構保存了一簇用於操做特定類型鍵值對的函數,例如計算哈希值、複製鍵、複製值、對比鍵、銷燬鍵和銷燬值的函數。而privdata
屬性則保存了須要傳給那些類型特定函數的可選參數。指針
爲了讓哈希表的負載因子維持在一個合理的範圍以內,當哈希表保存的鍵值對數量太多或者太少時,程序須要對哈希表的大小進行相應的擴展或者收縮。code
ht[0].used*2
的;ht[O].used
的。字典採用漸進式rehash,好處在千它採起分而治之的方式,將 rehash鍵值對所需的計算工做均攤到對字典的每一個添加、刪除、查找和更新操做上。cdn
跳躍表能夠用於有序集合鍵的底層實現,數據結構以下
zskiplist
結構包含如下屬性:
header
: 指向跳躍表的表頭節點。tail
: 指向跳躍表的表尾節點。level
: 記錄目前跳躍表內,層數最大的那個節點的層數。length
: 記錄跳躍表的長度。zskiplistNode 結構,該結構包含如下屬性:
level
) : 每一個層都帶有兩個屬性:前進指針和跨度。前進指針用於 訪問位於表尾方向的其餘節點,而跨度則記錄了前進指針所指向節點和當前節點的 距離。backward
) 指針:指向位於當前節點的前一個節點。score
): 節點按各自所保存的分值從小到大排列。obj
): 節點所保存的成員對象。當一個集合只包含整數值元素,而且這個集合的元素數董很少時, Redis 就會使用整數集合做爲集合鍵的底層實現。
contents
數組是整數集合的底層數據存放位置,各個項在數組中按值的大小從小到大有序地排列,而且數組中不包含任何重複項。length
屬性記錄了整數集合包含的元素數量,encoding
屬性決定了整數類型(INTSET_ENC_INT16
/INTSET_ENC_INT32
/INTSET_ENC_INT64
)。新元素的類型比整數集合現有全部元素的類型都要長時,整數集合須要先進行升級。
若是列表鍵或者哈希鍵包含的元素比較少,那麼會採用壓縮列表做爲底層實現。
屬性 | 說明 |
---|---|
zlbytes |
記錄整個壓縮列表佔用的內存字節數 |
zltail |
記錄壓縮列表表尾節點距離壓縮列表的起始地址有多少字節 |
zllen |
記錄了壓縮列表包含的節點數量 |
entryX |
壓縮列表包含的各個節點 |
zlend |
特殊值 OxFF (十進制 255), 用於標記壓縮列表的末端 |
entryX的數據結構以下
節點的previous_entry_length
記錄了壓縮列表中前一個節 點的長度,節點的encoding
屬性記錄了節點的content
屬性所保存數據的類型以及長度,節點的content
屬性負責保存節點的值。
Redis對象的結構體定義以下
type爲對象類型,encoding爲底層使用的數據結構,而ptr是指向底層數據結構的指針。Redis一共支持了五種數據類型,能夠使用TYPE
命令查看對象的類型。
對象 | 對象type屬性的值 | TYPE命令的輸出 |
---|---|---|
字符串對象 | REDIS_STRING | "string" |
列表對象 | REDIS_LIST | "list" |
哈希對象 | REDIS_HASH | "hash" |
集合對象 | REDIS_SET | "set" |
有序集合對象 | REDIS_ZSET | "zset" |
而對象具體使用的數據結構能夠用OBJECT ENCODING
命令獲取。
類型 | 編碼 | 對象 |
---|---|---|
REDIS_STRING | REDIS_ENCODING_INT | 使用整數值實現的字符串對象 |
REDIS_STRING | REDIS_ENCODING_EMBSTR | 使用 embstr 編碼的簡單動態字符串實現的字符串對象 |
REDIS_STRING | REDIS_ENCODING_RAW | 使用簡單動態字符串實現的字符串對象 |
REDIS_LIST | REDIS_ENCODING_ZIPLIST | 使用壓縮列表實現的列表對象 |
REDIS_LIST | REDIS_ENCODING_LINKEDLIST | 使用雙端鏈表實現的列表對象 |
REDIS_HASH | REDIS_ENCODING_ZIPLIST | 使用壓縮列表實現的哈希對象 |
REDIS_HASH | REOIS_ENCODING_HT | 使用字典實現的哈希對象 |
REDIS_SET | REDIS_ENCODING_INTSET | 使用整數集合實現的集合對象 |
REDIS_SET | REDIS_ENCODING_HT | 使用字典實現的集合對象 |
REDIS_ZSET | REDIS_ENCODING_ZIPLIST | 使用壓縮列表實現的有序集合對象 |
REDIS_ZSET | REDIS_ENCODING_SKIPLIST | 使用跳躍表和字典實現的有序集合對象 |
不一樣類型的對象的編碼選擇規則以下:
當列表對象能夠同時知足如下兩個條件時,列表對象使用ziplist
編碼:
不能知足這兩個條件的列表對象須要使用 linkedlist 編碼。
當哈希對象能夠同時知足如下兩個條件時,哈希對象使用 ziplist 編碼:
不能知足這兩個條件的哈希對象須要使用 hash able 編碼。
當集合對象能夠同時知足如下兩個條件時,對象使用 intset 編碼: 集合對象保存的全部元素都是整數值;
不能知足這兩個條件的集合對象須要使用 hash table 編碼。
當有序集合對象能夠同時知足如下兩個條件時,對象使用ziplist
編碼:
不能知足以上兩個條件的有序集合對象將使用skiplist
編碼。
有序集合對象在維護skiplist
的同時,使用了dict
,使得可以快速完成成員查詢。