String 資料結構
首先我來看下, Redis 中 String 的資料結構:
我們稱之為 SDS (Simple Dynamic String) 簡單動態字串
struct sdshdr {
//記錄buf陣列中已經使用的位元組數(等價于字串的長度strlen)
int len;
//記錄buf陣列中未使用的位元組數(用于動態擴容)
int free;
//位元組陣列,用于保存字串
char buf[];
}
對比C語言字串:
-
優化了獲取字串長度的時間復雜度為: O(1)
因為 SDS 維護了一個 len 欄位,這個欄位的設定和更新是由 SDS 的 API 在執行時自動完成的,
-
杜絕緩沖區溢位
在使用 c 語言函式 strcat(s1, " Cluster") (在 s1 字串后面拼接另一個字串) 時,如果忘記提前為 s1 分配足夠的空間,那么 strcat 函式執行之后, 將會導致s1后面的空間內容被意外修改,
而 Redis 在對 SDS 修改時,會提前檢查長度時候足夠,才執行相關操作, 如果長度不夠,會先擴展 s 的空間, 再執行 -
減少記憶體重分配
在 SDS 維護了 free 欄位,可以知道未使用的位元組數,這樣在動態擴充字串時可以根據這個值判斷要不要重新分配記憶體
-
二進制安全
C語言是依靠 \0 作為字串的結束標志的,這意味著字串中間不能再次包含 \0 字符, 而 SDS 記錄了字串的實際長度, 所以它可以做更多的事情, 比如保存圖片
-
兼容部分 C字串函式
雖然 SDS 是 二進制安全的,但他們都遵守在字串末尾額外分配一個位元組容納 \0 當結尾,這就是為了讓那些保存文本資料的 SDS 可以重用 <string.h> 庫
RedisObject 資料結構
在redis中存盤的每個物件都表示為一個redisObject,它記錄了這個物件的資料型別,編碼方式,指向實際內容的指標等
typedef struct redisObject {
// 型別 4bits (String,Hash,Set,List等)
unsigned type:4;
// 編碼方式 4bits (int, embstr, raw 等)
unsigned encoding:4;
// LRU 時間(相對于 server.lruclock) 24bits
unsigned lru:22;
// 參考計數 Redis里面的資料可以通過參考計數進行共享 32bits
int refcount;
// 指向實際存盤的物件 (比如:指向一個SDS字串物件) 64bits
void *ptr;
} robj;
String的三種編碼方式
-
int
當保存的值為整數且值的大小不超過long的范圍,使用整數存盤
-
embstr
當字串長度不超過44個位元組時,使用embstr編碼
(只實作一次分配記憶體空間,只允許讀,若修改資料,就會轉成raw編碼) -
raw
大于44位元組時,用raw編碼
int編碼不必多說,為了數值計算方便
為什么要分為 embstr 和 raw 呢?
首先來張圖,直觀感受下,這2種存盤方式的記憶體布局:

- embstr 是連續存盤的,也就是說 RedisObject 物件頭 和 SDS 字串的實際內容 是連續在一起存盤的,也就是 RedisObject 中的ptr 指向的內容,就緊跟著在后面 (只要分配1次記憶體)
- raw 是不連續存盤的, ptr 指向的內容,是單獨分配的(要分配2次記憶體)
這么做的原因當然是為了性能考慮,Redis考慮到多數字串,可能都不會很長, 這樣使用 embstr 只需分配一次記憶體(也很小),而且還是連續的存盤,性能很高,也有利于減少記憶體碎片
String編碼演示
- 使用
TYPE key查看物件的資料型別 - 使用
OBJECT ENCODING key查看物件的編碼方式
演示 int 編碼:
127.0.0.1:6379> set age 100
OK
127.0.0.1:6379> type age
string
127.0.0.1:6379> object encoding age
"int"
演示 embstr 編碼:
127.0.0.1:6379> SET name tom
OK
127.0.0.1:6379> TYPE name
string
127.0.0.1:6379> OBJECT ENCODING name
"embstr"
演示 raw 編碼:
127.0.0.1:6379> set name sdsdnjjkasjdnnjasjdnasldklaksdkkansndmasdulasndnkadashdahsdhkpasduasdybasbdvcfaffafkgsaas
OK
127.0.0.1:6379> type name
string
127.0.0.1:6379> object encoding name
"raw"
String的常用命令
- SET: 添加或修改一個已經存在的String型別的鍵值對
- GET: 根據key獲取String型別的value
- INCR: 讓一個整形存盤的String型別的value自增1
- INCRBY: 讓一個整形存盤的String型別的value自增指定的步長, 例如 incrby num 2, 讓num的值自增2
- INCRBYFLOAT: 讓一個浮點型別的數值自增指定的步長
- SETNX: 添加一個String型別的鍵值對,前提是這個key不存在,否則不執行(可用于實作分布式鎖)
- SETEX: 添加一個String型別的鍵值對,并且指定超時時間
- 更多 String 命令,請查閱 官方檔案
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/497007.html
標籤:.NET技术
上一篇:用WindowsAppSDK(WASDK)優雅的開發上位機應用
下一篇:Redis 原理 - List
