這周開始學習 Redis,看看Redis是怎麼實現的。所以會寫一系列關於 Redis的文章。這篇文章關於 Redis 的基礎資料。閱讀這篇文章你可以瞭解:
- 動態字串(SDS)
- 連結串列
- 字典
三個資料結構 Redis 是怎麼實現的。
SDS
SDS (Simple Dynamic String)是 Redis 最基礎的資料結構。直譯過來就是”簡單的動態字串“。Redis 自己實現了一個動態的字串,而不是直接使用了 C 語言中的字串。
sds 的資料結構:
struct sdshdr {
// buf 中已佔用空間的長度
int len;
// buf 中剩餘可用空間的長度
int free;
// 資料空間
char buf[];
};
複製程式碼
所以一個 SDS 的就如下圖:
所以我們看到,sds 包含3個引數。buf 的長度 len,buf 的剩餘長度,以及buf。
為什麼這麼設計呢?
-
可以直接獲取字串長度。
C 語言中,獲取字串的長度需要用指標遍歷字串,時間複雜度為 O(n),而 SDS 的長度,直接從len 獲取複雜度為 O(1)。 -
杜絕緩衝區溢位。
由於C 語言不記錄字串長度,如果增加一個字元傳的長度,如果沒有注意就可能溢位,覆蓋了緊挨著這個字元的資料。對於SDS 而言增加字串長度需要驗證 free的長度,如果free 不夠就會擴容整個 buf,防止溢位。 -
減少修改字串長度時造成的記憶體再次分配。
redis 作為高效能的記憶體資料庫,需要較高的相應速度。字串也很大概率的頻繁修改。 SDS 通過未使用空間這個引數,將字串的長度和底層buf的長度之間的額關係解除了。buf的長度也不是字串的長度。基於這個分設計 SDS 實現了空間的預分配和惰性釋放。- 預分配
如果對 SDS 修改後,如果 len 小於 1MB 那 len = 2 * len + 1byte。 這個 1 是用於儲存空位元組。
如果 SDS 修改後 len 大於 1MB 那麼 len = 1MB + len + 1byte。 - 惰性釋放
如果縮短 SDS 的字串長度,redis並不是馬上減少 SDS 所佔記憶體。只是增加 free 的長度。同時向外提供 API 。真正需要釋放的時候,才去重新縮小 SDS 所佔的記憶體
- 預分配
-
二進位制安全。
C 語言中的字串是以 ” “ 作為字串的結束標記。而 SDS 是使用 len 的長度來標記字串的結束。所以SDS 可以儲存字串之外的任意二進位制流。因為有可能有的二進位制流在流中就包含了” “造成字串提前結束。也就是說 SDS 不依賴 “