redis設計與實現

2021-09-25 09:48:00 字數 3654 閱讀 1383

物件所使用的底層資料結構

編碼常量

object encoding 命令輸出

整數redis_encoding_int"int"

embstr編碼的簡單動態字串(sds)

redis_encoding_embstr"embstr"

簡單動態字串

redis_encoding_raw"raw"

字典redis_encoding_ht"hashtable"

雙端鍊錶

redis_encoding_linkedlist"linkedlist"

壓縮列表

redis_encoding_ziplist"ziplist"

整數集合

redis_encoding_intset"intset"

跳躍表和字典

redis_encoding_skiplist"skiplist"

每種型別的物件都至少使用了兩種不同的編碼

型別編碼

物件redis_stringredis_encoding_int使用整數值實現的字串物件。

redis_stringredis_encoding_embstr使用embstr編碼的簡單動態字串實現的字串物件。

redis_stringredis_encoding_raw使用簡單動態字串實現的字串物件。

redis_listredis_encoding_ziplist使用壓縮列表實現的列表物件。

redis_listredis_encoding_linkedlist使用雙端鍊錶實現的列表物件。

redis_hashredis_encoding_ziplist使用壓縮列表實現的雜湊物件。

redis_hashredis_encoding_ht使用字典實現的雜湊物件。

redis_setredis_encoding_intset使用整數集合實現的集合物件。

redis_setredis_encoding_ht使用字典實現的集合物件。

redis_zsetredis_encoding_ziplist使用壓縮列表實現的有序集合物件。

redis_zsetredis_encoding_skiplist使用跳躍表和字典實現的有序集合物件。

redis 資料庫裡面的每個鍵值對(key-value pair)都是由物件(object)組成的:

redis 沒有直接使用 c 語言傳統的字串表示(以空字元結尾的字元陣列,簡稱 c 字串), 而是自己構建了一種名為簡單動態字串(****** dynamic string,sds)的抽象型別, 並將 sds 用作 redis 的預設字串表示。

c 語言使用長度為n+1的字元陣列來表示長度為n的字串, 並且字元陣列的最後乙個元素總是空字元'\0'

因為 c 字串並不記錄自身的長度資訊, 所以為了獲取乙個 c 字串的長度, 程式必須遍歷整個字串, 對遇到的每個字元進行計數, 直到遇到代表字串結尾的空字元為止, 這個操作的複雜度為 o(n)

sds 在len屬性中記錄了 sds 本身的長度, 所以獲取乙個 sds 長度的複雜度僅為 o(1)

sds 的空間分配策略完全杜絕了發生緩衝區溢位的可能性: 當 sds api 需要對 sds 進行修改時, api 會先檢查 sds 的空間是否滿足修改所需的要求, 如果不滿足的話, api 會自動將 sds 的空間擴充套件至執行修改所需的大小, 然後才執行實際的修改操作, 所以使用 sds 既不需要手動修改 sds 的空間大小, 也不會出現前面所說的緩衝區溢位問題

當 sds 的 api 對乙個 sds 進行修改, 並且需要對 sds 進行空間擴充套件的時候, 程式不僅會為 sds 分配修改所必須要的空間, 還會為 sds 分配額外的未使用空間。通過空間預分配策略, redis 可以減少連續執行字串增長操作所需的記憶體重分配次數。

通過空間預分配策略, redis 可以減少連續執行字串增長操作所需的記憶體重分配次數。

在擴充套件 sds 空間之前, sds api 會先檢查未使用空間是否足夠, 如果足夠的話, api 就會直接使用未使用空間, 而無須執行記憶體重分配。

通過這種預分配策略, sds 將連續增長n次字串所需的記憶體重分配次數從必定n次降低為最多n次。

惰性空間釋放用於優化 sds 的字串縮短操作: 當 sds 的 api 需要縮短 sds 儲存的字串時, 程式並不立即使用記憶體重分配來**縮短後多出來的位元組, 而是使用free屬性將這些位元組的數量記錄起來, 並等待將來使用。

sds 的 api 都是二進位制安全的(binary-safe): 所有 sds api 都會以處理二進位制的方式來處理 sds 存放在buf陣列裡的資料, 程式不會對其中的資料做任何限制、過濾、或者假設 —— 資料在寫入時是什麼樣的, 它被讀取時就是什麼樣。

sds 使用len屬性的值而不是空字元來判斷字串是否結束;

c 字串

sds獲取字串長度的複雜度為 o(n) 。

獲取字串長度的複雜度為 o(1) 。

api 是不安全的,可能會造成緩衝區溢位。

api 是安全的,不會造成緩衝區溢位。

修改字串長度n次必然需要執行n次記憶體重分配。

修改字串長度n次最多需要執行n次記憶體重分配。

只能儲存文字資料。

可以儲存文字或者二進位制資料。

可以使用所有庫中的函式。

可以使用一部分庫中的函式。

redis 的鍊錶實現的特性可以總結如下:

使用雜湊表作為底層實現, 乙個雜湊表裡面可以有多個雜湊表節點, 而每個雜湊表節點就儲存了字典中的乙個鍵值對。

redis 就會使用跳躍表來作為有序集合鍵的底層實現

當乙個集合只包含整數值元素, 並且這個集合的元素數量不多時, redis 就會使用整數集合作為集合鍵的底層實現。

整數集合(intset)是 redis 用於儲存整數值的集合抽象資料結構, 它可以儲存型別為int16_tint32_t或者int64_t的整數值, 並且保證集合中不會出現重複元素。

Redis 設計與實現

本書的目標是以簡明易懂的方式講解 redis 的內部執行機制,通過閱讀本書,你可以了解到 redis 從資料結構到伺服器構造在內的幾乎所有知識。為了保證內容的簡潔性,本書會盡量以高抽象層次的角度來觀察 redis 並將 的細節留給讀者自己去考究。如果讀者只是對 redis 的內部運作機制感興趣,但並...

《redis設計與實現》

提高系統架構的效能,增加快取層是常見的優化方式,redis和memcache是當前採用較多的快取元件,redis被稱為資料結構資料庫 redis和memcache的區別 redis和memcahce都是基於記憶體的key value儲存 memcache的事件模型是多執行緒reactor模型,效能更...

Redis設計與實現(一)

redis是一種現在挺火的一種nosql資料庫,它一般被用作快取。比如我們可以在redis客戶端敲 redis set msg helloredis 那麼就會在redis資料庫中建立乙個新的鍵值對,keg是msg,value是helloredis,兩個都是sds。又比如在redis客戶端敲 redi...