1. 程式人生 > 其它 >Redis | 簡單動態字串(SDS)

Redis | 簡單動態字串(SDS)

簡單動態字串

​ Redis 沒有直接使用C語言的字串,而是自己構建了一個名為簡單動態字串的掃象類(SDS),並將SDS做為Redis的預設字串。

​ C語言的字串,在Redis中,只會做一些日誌處理的工作,因為這些工作不需要對字串進行修改。而需要修改的字串的都會採用 SDS。

比如下面這個例子:

    set msg "hello,world"

​ 這個命令是一個簡單的儲存命令,鍵是 msg 值是 hello,world,這個動作會在資料庫中建立一個新的鍵值對。

那麼這個鍵值對的鍵和值都是由 SDS 實現的。

SDS 除了用來儲存資料庫的物件以外,還被用做資料庫的緩衝區的實現。

SDS 結構的定義

  struct sdshdr{
    // 陣列中已儲存的字元長度
    int len;
    // 陣列中還未使用的長度
    int free;
    // 字切陣列,用於儲存字串
    char buf[];
  }

​ 在buf陣列中,最後一位永遠都是/0 ,這一位也不會記入陣列的長度中,對我們使用者來說,可以完全當它不存在,但是這個/n 存在的好處卻是非常大的,因為C語言的字串本來未尾就自帶了一個 /0 ,Redis 的SDS 後面也加一個數組 ,可以使Redis 完全可以重用C語言字串的API。

SDS 和 C語言原生字串的比效

1、獲取字串長度

​ 原生字串獲取長度的時間複雜度為 O(n) , 因為它沒有記錄自身長度的欄位,所以如果想要獲取字串的長度,就必須要遍歷整個字串,直到遇到 /0

為止,才會返回,而SDS的 len 屬性中本來就維護了一個自身長度的屬性,所以獲取 SDS 長度的時間複雜度為 o(1)。

​ 並且 SDS 的統計字串的長度工作是在執行APi的時候 ,自動執行的,並且不需要我們手動設定,可以方便我們的使用,所以這保證了獲取字串長度的工作不會使Redis 陷入效能瓶頸,就算一直對一個字串一直使用 STRLEN 命令,也不會造成任何影響 ,因為Redis 獲取字串長度的命令,時間複雜度僅為 O(1)。

2、保證快取區不會益出

​ 使用C語言原生字串的害處就是,如果修改一個字串的時候,忘讓給他重新分配空間,可能導致緩衝區益出,並且會覆蓋別的資料。

​ 在使用SDS的時候 ,則不會出現這個情況,因為每一次修改SDS字串的時候 ,都會先檢查free屬性,檢視空間是否足夠。如果不夠的話,則會先對SDS進行擴容,然後才是對字串進行修改。

​ 如果是在別的應用中,如果每一次修改字串時去擴容或者縮容,是完全可以理解的,但是Redis是一個數據庫,無法忍受這樣效能浪費,所以每一次擴容的時候,都會為下一次修改預留空間,分配的規則如下:

如果SDS 的長度小於 1M,那麼每一次增加的空間長度為此時len的長度,增加後 free 和 len 的長度應該是一樣的。此時的長度計算為: free + len + 1

如果SDS 的長度大於 1M ,那麼每一次增加 1M 的空閒空間,此時SDS的長度為:len + 1M + 1

​ 因為通過空間預分配,所以Redis 可以減少連續執行字串增長操作所需要的記憶體重新分配次數,並且這些分配的空間,並不會因為字串的縮短而被回收,而是會留在SDS中,以防止未來會有這一方面的需要。並且我們也不需要擔心這些空間會對記憶體造成什麼影響,SDS 的APi會在真正有用的時候 ,對這些空間進行釋放。

二進位制安全

​ 我們在使用Redis 的時候 ,可以直接儲存圖片,視訊,音樂。。。那是因為Redis存在buf裡面的資料是二進位制的,並不是簡單的字串,也不會對二進位制資料進行處理,過濾等操作,這也保證了,我們存入資料的時候是什麼樣,讀取資料的時候就是什麼樣。

​ 而C語言就不可以這樣了,因為C語言會預設以 /0 字元進行分割字串,所以便得C字串除了結尾包含空字元外,中間的字元都不能包含這樣的字元,這就極大的限制了C原生字串的使用範圍。



細節決定成敗!
個人愚見,如有不對,懇請扶正!