我們知道redis是乙個鍵值對資料庫,當你執行如下命令時
set testkey testvalue;
其中的鍵就是用sds(****** dynamic string,簡單動態字串)來實現的,redis中string類的值也是用sds實現的(如上面的testvalue)。我們來看一下sds的底層資料結構是啥?
struct sdshdr
;
如下是乙個sds的示例
free:free為0,表示未使用的空間
len:這個sds儲存了5位元組長的字串
buf:char型別的陣列,前5個位元組是字串,後乙個位元組是\0,表示結尾,\0不計入總長度
當要存的字串變大或者變小的時候,會造成頻繁的記憶體分,進而影響效能。所以redis通過空間預分配和惰性空間釋放策略來避免記憶體的頻繁分配
空間預分配
當sds的內容變大時,程式不僅會為sds分配修改所需要的空間,還會為sds分配額外的未使用的空間。
對sds進行修改之後,sds的長度(即len屬性的值)小於1mb,程式分配和len屬性同樣大小的未使用空看,即sds len屬性的值和free屬性的值相同
對sds進行修改之後,sds的長度(即len屬性的值)大於等於1mb,程式會分配1mb的未使用空間
惰性空間釋放
當sds內容變小時,程式並不會釋放縮短後剩餘的空間,只是修改free屬性,將未使用字元數量記錄下來,等以後使用
上面的結構有改進的空間嗎?如果讓你來寫sds,你會怎麼寫呢?
不同長度的字串是否有必要占用相同大小的頭部?
當字串很小的時候,我們還得額外的使用8個位元組(len和free各佔4個位元組),感覺有點太浪費了。
我們是否可以根據字串的長度,來決定len和free占用的位元組數呢?比如短字串len和free的長度為1位元組就夠了。長字串,用2位元組或4位元組,更長的字串,用8位元組。
那我們如何區分這3種情況呢?
很簡單,再加乙個一位元組的字段標明型別就行了
所以在redis 3.2中,有如下5種型別
struct __attribute__ (
(__packed__)
) sdshdr5
;struct __attribute__ (
(__packed__)
) sdshdr8
;struct __attribute__ (
(__packed__)
) sdshdr16
;struct __attribute__ (
(__packed__)
) sdshdr32
;struct __attribute__ (
(__packed__)
) sdshdr64
;
len:buf陣列中已使用字元的數量
alloc:buf陣列中已分配字元的數量
flags:標識當前結構體的型別,低3位用作標識位,高5位預留(3個位元組能儲存的種類數為2的3次方即8,sds總共的種類數為5,所以用低三位就能用標識種類)
buf:字元陣列,用來儲存字串
可以看到sdshdr5比較特殊,並沒有len和alloc兩個字段,那它是如何存已使用和已分配的數量呢?
sdshdr5中,flags占用乙個位元組,低3位表示type,高5位表示長度,能表示的區間長度為(0~31,即25-1)
sdshdr5並沒有存在alloc的值,因此它不會進行空間預分配和惰性空間空間釋放,長度變動每次都重新申請記憶體
當字串長度大於31時,flags的後5位就存不下了,所以我們就將len和free單獨存放
Redis 底層資料結構詳解
前面介紹過redis的五大基礎資料型別 string hash list set zset 由六種底層資料結構 簡單動態字串 鍊錶 字典 跳躍表 整數集合 壓縮列表 實現,本章主要分析這六種底層資料結構。ps redis有八種編碼,但底層資料機構是六種。結構定義 struct sdshdrsds儲存...
redis內部資料結構的資料結構
redis對外的公眾的資料結構有五種string,list,set,hash,zset 編碼常量 編碼所對應的底層資料結構 redis encoding int long 型別的整數 redis encoding embstr embstr 編碼的簡單動態字串 redis encoding raw ...
Redis 的資料結構
redis是乙個先進的key value鍵值儲存資料庫,通常作為資料結構伺服器。支援strings,hashes,lists,sets,sorted sets,bitmaps 和hyperloglogs redis的字串為sds dynamic string 可以儲存任何東西,最大長度可達515兆。...