Redis字串型別內部編碼剖析

2021-09-11 09:15:26 字數 4075 閱讀 2919

我們平時用 redis都是處於使用者層面,我們可能會不加思索地操作乙個 key-value 對來方便地訪問資料,感覺方便之至。但你知道這些資料在背後是如何儲存以及編碼的嗎? 了解清楚了這個問題,將對我們更加高效地使用 redis具有指導意義。本文開始我們將結合 redis原始碼來逐個**redis五大資料型別的內部編碼機制。

對於 redis的常用5種資料型別(string、hash、list、set、sorted set),每種資料型別都提供了最少兩種內部的編碼格式,而且每個資料型別內部編碼方式的選擇對使用者是完全透明的,redis會根據資料量自適應地選擇較優化的內部編碼格式。

如果想檢視某個鍵的內部編碼格式,可以使用object encoding keyname指令來進行,比如:

127.0.0.1:6379> 

127.0.0.1:6379> set foo bar

ok127.0.0.1:6379>

127.0.0.1:6379> object encoding foo // 檢視某個redis鍵值的編碼

"embstr"

127.0.0.1:6379>

127.0.0.1:6379>

複製**

redis的每個鍵值內部都是使用乙個名字叫做redisobject這個 c語言結構體儲存的,其**如下:

解釋如下:

#define obj_encoding_raw 0        /* raw representation */

#define obj_encoding_int 1 /* encoded as integer */

#define obj_encoding_ht 2 /* encoded as hash table */

#define obj_encoding_zipmap 3 /* encoded as zipmap */

#define obj_encoding_linkedlist 4 /* no longer used: old list encoding. */

#define obj_encoding_ziplist 5 /* encoded as ziplist */

#define obj_encoding_intset 6 /* encoded as intset */

#define obj_encoding_skiplist 7 /* encoded as skiplist */

#define obj_encoding_embstr 8 /* embedded sds string encoding */

#define obj_encoding_quicklist 9 /* encoded as linked list of ziplists */

複製**

本文我們就從 redis最基本的 string型別的內部編碼開始**!

字串是 redis最基本的資料型別,redis 中字串物件的編碼可以是intraw或者embstr中的某一種,分別介紹如下:

我們不妨來做個實驗實際看一下:

實際情況就是 redis 內部會根據使用者給的不同鍵值而使用不同的編碼格式,而這一切對使用者完全透明!

redis 是使用sds(「簡單動態字串」)這個結構體來儲存字串,**裡定義了5種sds結構體:

struct __attribute__ ((__packed__)) sdshdr5 ;

struct __attribute__ ((__packed__)) sdshdr8 ;

struct __attribute__ ((__packed__)) sdshdr16 ;

struct __attribute__ ((__packed__)) sdshdr32 ;

struct __attribute__ ((__packed__)) sdshdr64 ;

複製**

可以看出,除了結構體欄位資料型別的不同,其欄位含義相差無幾,其中:

了解了這些基本的資料結構以後,我們就來看看上面例子中:

這三種情形下 redis 內部到底是怎麼存資料的!

命令示例:set foo 123

當字串鍵值的內容可以用乙個64位有符號整形來表示時,redis會將鍵值轉化為 long型來進行儲存,此時即對應obj_encoding_int編碼型別。

obj_encoding_int編碼型別內部的記憶體結構可以形象地表示如下:

而且 redis 啟動時會預先建立10000個分別儲存0~9999的 redisobject 變數作為共享物件,這就意味著如果 set字串的鍵值在 0~10000 之間的話,則可以直接指向共享物件而不需要再建立新物件,此時鍵值不佔空間!

因此,當執行如下指令時:

set key1 100

set key2 100

複製**

其實key1key2這兩個鍵值都直接引用了乙個 redis 預先已建立好的共享 redisobject 物件,就像下面這樣:

原始碼之前,了無秘密,我們再對照下面的原始碼,來理解一下上述過程

命令示例:set foo abc

redis 在儲存長度小於44位元組的字串時會採用obj_encoding_embstr編碼方式,口說無憑,我們來瞅瞅原始碼:

從上述**中很容易看出,對於長度小於 44的字串,redis 對鍵值採用obj_encoding_embstr方式,embstr 顧名思義即:embedded string,表示嵌入式的string。從記憶體結構上來講 即字串 sds結構體與其對應的 redisobject 物件分配在同一塊連續的記憶體空間,這就彷彿字串 sds 嵌入在 redisobject 物件之中一樣,這一切從下面的**即可清楚地看到:

因此,對於指令set foo abc所設定的鍵值,其記憶體結構示意圖如下:

指令示例:set foo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx

正如指令示例,當字串的鍵值為長度大於44超長字串時,redis 則會將鍵值的內部編碼方式改為obj_encoding_raw格式,這與上面的obj_encoding_embstr編碼方式的不同之處在於 此時動態字串 sds 的記憶體與其依賴的 redisobject 的記憶體不再連續了,以set foo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx為例,其鍵值的記憶體結構如下所示:

到此就講完了最基本的string資料型別的內部編碼情況,怎麼樣,還是挺好理解的吧!

後續我們將繼續剖析 redis 中 hash 資料型別的內部編碼格式。

由於能力有限,若有錯誤或者不當之處,還請大家批評指正,一起學習交流!

如果有興趣,也可以抽點時間看看作者一些關於容器化、微服務化方面的文章:

長按掃瞄下面的小心心來訂閱codesheep,獲取更多務實、能看懂、可復現的原創文 ↓↓↓

redis中字串型別

字串型別是redis中最基本的資料型別,它能儲存任何形式的字串,包括二進位制資料。你可以用其儲存使用者的手機號,郵箱,json化後的物件甚至是。在ifuchuan型別中鍵允許儲存的資料的最大容量是512mb。字串型別是其它4種資料型別的基礎,其他資料型別和字串型別的差別從某種角度來說只是組織字串的形...

Redis的字串型別

字串是 redis 中最常用的資料結構。字串型別的值,簡單字串,json xml,數字,二進位制 等 最大 512mb 大小。set key value ex seconds px milliseconds nx xx ex 為鍵設定秒級過期時間 px 為鍵設定毫秒級過期時間 nx 鍵必須不存在,才...

Redis儲存型別 字串

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