Redis的底層字串儲存 SDS

2021-08-14 08:45:32 字數 2641 閱讀 3336

我們知道redis資料庫是使用c語言寫的,然而其內部的字串的儲存卻並不是使用傳統的c語言字串表示,而是使用一種名為簡單動態字串(****** dynamic string,sds)的抽象資料型別。

首先我們來對sds有乙個大概的認識

如果我們客戶端執行如下命令

127.0.0.1:6381> set msg "hello world"
那麼redis將會在資料庫中建立乙個新的鍵值對,其中:

鍵值對的鍵是乙個字串物件,物件的底層的實現是乙個儲存著"msg"的sds

同樣,鍵值對的值的底層的實現就是乙個儲存著"hello world"的sds

sds除了用來儲存資料庫中的字串之外,sds還被用作緩衝區(buffer),如aof模組中的aof緩衝區,以及客戶端狀態中的輸入緩衝區

接下來我們來看一看sds的定義

struct sdshdr;
其中buf陣列的大小等於len+free+1,其中加一的為末尾的標識 『\0』

如下sds的儲存示例

其中free=3就是還有三個位元組的空間未分配,len=5就是儲存的字串redis的長度,而我們可以很明顯的看出buf的長度為free+len+1=9

那麼sds與傳統的c語言字串的區別有哪些呢?

首先由於sds的結構中有對應的freelen屬性來記錄相應的字串的長度,所以獲取sds字串長度的時間複雜度為o(

1),而傳統的c語言字串則需要遍歷一遍字串從而得到其長度(時間複雜度為o(

n))。

sds並不會使得緩衝區溢位

我們知道傳統的c語言字串會導致溢位,因為其不會檢查當前字元陣列剩餘空間的大小。

而sds的記憶體分配策略則解決了這一問題,比如說當我們使用sdscat()函式在當前的字串後面拼接字串時,會檢查給定的空間是否夠用,如果不夠則會事先擴充sds的空間大小。

頻繁的記憶體分配和記憶體**就會帶來效能問題,為此,redis分別實現了空間預分配惰性空間兩種優化策略。

空間預分配

空間預分配用於優化sds的字串的增長操作:當sds的api對乙個sds字串進行修改,並且此時sds的空間不夠的時候,系統不僅會為sds分配增長所必要的空間,還會分配額外的未使用的空間,其規則如下

我們拿上面的第一點規則進行圖示講解

如有如下的sds字串,其使用空間為5,未使用空間為3

現在使用sdscat(str," dbase")進行拼接操作,這時候就需要分配額外空間

這時候分配記憶體後len=11,所以系統就會再額外的分配11位元組的未使用空間,於是free=11

惰性空間釋放

空間預分配用於優化sds的字串的縮短操作:當sds的api對乙個sds字串進行縮短時,程式並不會立即**多餘的未使用的空間,而是通過會增加free屬性的值,將未使用的空間記錄下來,並等待將來使用。

我們使用sdstrim()函式來做乙個示例

現在執行sdstrim(str,"xy"),來移除str中的所有'x''y'字元

這樣得到的結果為

看到上面我們就知道通過sdstrim(str,"xy")縮短字串後多餘的8個位元組的空間並沒有被**掉,而是將free的值加了8從而記錄下了多餘的空間,從而可以再次利用。

此外,sds還是二進位制安全的,因為sds字串是通過len的大小判斷字串結束的(不是通過'\0'),從而其中可以儲存'\0',這就是說其可以儲存任意格式的二進位制資料。

那麼為什麼還要在sds字串的末尾加上乙個'\0'呢?

這是因為為了使sds字串相容部分的c語言字串函式,比如說中過的函式,從而避免了**的重複,達到重用的效果。

Redis字串的底層設計

redis的底層是用c語言來實現的,在c語言中字串的預設是以 0 標識結束,而redis並沒有採用這種傳統的方法表示,而是自己構建了一種簡單動態字串 sds 來表示。下面看一下什麼是sds,sds的 定義,以及在儲存乙個字串 redis 時sds和傳統c的表示分別是怎麼樣,使用sds的好處是什麼 s...

Redis的底層實現 字串章節

不要遺忘最初的目標。ruider 總結 about me redis的命令如下 set x hello get x helloredis作為一種儲存字串的快取結構,其具體實現是由c語言完成,在c語言中,字串是通過字元陣列實現的,即char,那麼redis對於字串的實現是不是也是基於字元陣列嗎?不是的...

Redis儲存型別 字串

string 是 redis 最基本的型別,string 型別是二進位制安全的。意思是 redis 的 string 可以包含任何資料。比如jpg或者序列化的物件。string 型別是 redis 最基本的資料型別,string 型別的值最大能儲存 512mb。設定指定 key 的值 set 獲取指...