程序員必讀源碼,Redis的精緻,在每個數據結構都體現出淋漓盡致

Redis 數據結構 程序員 C語言 操作系統 設計 沙茶敏碎碎念 2019-07-03

今天我們來聊一聊Redis裡面的一個基礎數據結構,字符串。在Redis中,字符串又叫做SDS,全稱為Simple Dynamic String,翻譯成中文就是簡單的動態字符串。我們來看看到底有多麼的簡單!

struct SDS<T> {
T capacity; // 數組的容量
T len; // 數組的長度
byte flags; // 特殊標識位
byte[] content; // 具體的字符串內容
}


程序員必讀源碼,Redis的精緻,在每個數據結構都體現出淋漓盡致


為什麼這裡要使用的是泛型T而不是直接使用int類型呢?作為節省內存到極致的Redis,對於長度較小的數據,能用short或者byte進行表示,不得不說,Redis真是斤斤計較!對於使用者來說,Redis可能只是緩存幾千幾萬個key,但對於Redis來說,可能要緩存多個業務幾百萬個數據,所以積少成多,還是非常有價值的。

我們知道,在C語言中,是沒有維護字符串數組的長度的,為什麼Redis需要維護這個字符串的長度呢?我們不煩想一個現實的問題,在C語言中,類似'\0'的字符,系統函數讀取到就認為是結束,所以像"abc'\0'dfg"這樣的字符串,在C語言的系統函數只能讀取到abc,如果我們不記錄數組的長度,就有可能讀取到被截斷的數據。所以,Redis的字符串設計,讓Redis的字符串是二進制安全的。除此之外,還避免了一些內存覆蓋的問題,每次修改字符串也不一定需要重新申請空間,而且O(1)級別地求出字符串的長度。


程序員必讀源碼,Redis的精緻,在每個數據結構都體現出淋漓盡致


我們再來討論一個有意思的事情,在Redis中,字符串竟然有兩種不同的存儲形式,一個是embstr一個是raw結構。這兩者有什麼不同呢?

在Redis中,每一個數據結構,都有一個頭部RedisObject,type是數據的類型,同一種類型有不同的存儲格式,例如字符串可能是emb也可能是raw,lru用來存儲內存淘汰的信息,refcount用來存引用計數的。而ptr用來指向SDS存儲的地址。struct RedisObject {
int4 type; // 0.5字節
int4 encoding; // 0.5字節
int24 lru; // 3字節
int32 refcount; // 4字節
void *ptr; // 8字節(如果是64位系統)
} robj;

總共16個字節,而前面的SDS,用來表示長度、容量、標識符總共為3字節,總共19字節,加上每個結構最後字節用來表示'\0'的特殊表示,總共20字節。為了減少內存碎片,redis每次都會向操作系統申請32/64/128等2的n次冪的內存空間,一64字節為分界線,Redis小於64-20=44個字節的字符串,就會使用emb存儲,否則就會使用raw進行存儲。


程序員必讀源碼,Redis的精緻,在每個數據結構都體現出淋漓盡致


為什麼Redis要這麼折騰呢?為什麼不全部按照raw的格式進行存儲呢?這裡留一道課後題給大家進行思考!歡迎大家關注我,近期還準備了一些AI相關的知識,整理後會和大家繼續分享。大家的支持是我繼續嘮嗑的動力。同名公眾號(沙茶敏碎碎念)

(此處已添加圈子卡片,請到今日頭條客戶端查看)

相關推薦

推薦中...