1. 程式人生 > >Redis之字串

Redis之字串

:本篇部落格為閱讀《Redis設計與實現》的讀書筆記

1 底層實現

Redis 的字串是利用 SDS 來表示的,其底層具體實現如下:

struct sdsdr{
    // 記錄 buf 陣列中已使用的位元組數量
    // 等於 SDS 所儲存字串的長度
    int len;
    // 記錄 buf 陣列中未使用位元組的數量
    int free;
    // 位元組陣列,用於儲存字串
    char buf[];
}

2 與 C 字串區別

2.1 獲取長度複雜度

C 的字串並沒有儲存長度,因此,每當需要獲取一個字串的長度時,需要進行一次遍歷,每次遍歷 +1,當遍歷到 ‘\0’ 字元時停止,這個時間複雜度為 O(N)。而 Redis 已經儲存了字串的長度,因此獲取長度的時間複雜度為 O(1)。

2.2 杜絕緩衝區溢位

因此 Redis 字串中利用 free 儲存了還可以儲存的字串,當需要新增字串時,會根據這個變數判斷是否有足夠的空間,如果沒有的話,就會對 buf 陣列進行擴充套件,這樣就可以避免緩衝區洩漏的問題了。

2.3 記憶體重分配

因為 Redis 中的資料是要被頻繁修改的,因此 SDS 需要在頻繁的修改下還能保持一定的效能,那麼可以從哪些地方優化呢?當需要新增一個字串,並且該字串的長度大於剩餘的空間(由 free 變數標識)時,Redis 需要對 buf 陣列進行擴充,怎麼樣才能減少擴充 buf 陣列的次數呢?Redis 提供了兩種分配策略:

  • 空間預分配

    當新增一個字串之後,Redis 會給該字串預留同等長度的空間。例如 SDS 儲存了 “Redis” 的字串,現在沒有剩餘空間,因此 free 欄位為 0,當需要再新增一個 “hello” 字串時,SDS 先擴充為可以儲存 10 字元的陣列,將 hello 儲存進 buf 陣列後,還會為 buf 陣列額外新增 10 個位元組作為儲存空間。
    這是 SDS 儲存字元小於 30MB 的情況,當 SDS 儲存長度大於 30MB 時,其額外提供的空間為 1 MB。
  • 惰性空間釋放
    上面的分配策略是在新增字串時提供的,當字串需要刪除其中的一些字元時,SDS 並不會將這些空間釋放出來,而是直接作為未使用空間儲存下來,這樣,當需要再次新增字串時,這些空間就可以用上了。

2.4 二進位制安全

C 的字串是根據 ‘\0’ 來判斷是否到達字串末尾,因為這個特性它是不能儲存圖片、音訊、視訊等二進位制資料的,而 Redis 中的字串是根據 len 變數判斷資料是否到達末尾了,因此它儲存二進位制資料並且可以讀取出來。

3. SDS API

這一部分可以檢視官方文件,就不一一列出了。