主頁 > 知識庫 > Redis字符串原理的深入理解

Redis字符串原理的深入理解

熱門標(biāo)簽:臺灣電銷 400電話辦理的口碑 地圖標(biāo)注工廠入駐 b2b外呼系統(tǒng) 四川穩(wěn)定外呼系統(tǒng)軟件 一個地圖標(biāo)注多少錢 廊坊外呼系統(tǒng)在哪買 南京手機外呼系統(tǒng)廠家 高碑店市地圖標(biāo)注app

前言

來掘進(jìn)都有兩年多了一直當(dāng)個小透明,今天終于發(fā)一次文章了.

最近在看 Redis,感覺收獲很多,寫篇博客記錄一下.

Redis 有五種基礎(chǔ)數(shù)據(jù)結(jié)構(gòu):string,list,set,zset,hash.其中 string是最最最簡單的也是最常用的.這個數(shù)據(jù)類型雖然簡單但是內(nèi)部的結(jié)構(gòu)設(shè)計卻很是精致.

基本介紹

相比于 Java,在 Redis 中 string 是可以修改的,是動態(tài)字符串(Simple Dynamic String 簡稱 SDS)他的內(nèi)部結(jié)構(gòu)更像是一個 ArrayList,維護(hù)一個字節(jié)數(shù)組并預(yù)分配冗余空間以減少內(nèi)存的頻繁分配.當(dāng)字符串的長度小于 1MB時,每次擴容都是加倍現(xiàn)有的空間,如果字符串長度超過 1MB 時,每次擴容時只會擴展 1MB 的空間.

ps:字符串長度為最大長度 512MB.

> set name test
OK
> get name
"test"
> mset name1 test1 name2 test2
OK
> mget name1 name2
1) "test1"
2) "test2"
> del name
(integer) 1

上面是字符串的基本操作 命令mset 和 mget 可以對多個字符串讀寫 節(jié)省網(wǎng)絡(luò)開銷

不僅如此redis 的字符串還可以用來儲存整數(shù)(更不像Java 的字符串了),并且可以自增操作.字符串保存整數(shù)類型的的范圍在 至
如果保存的數(shù)大于這個取值范圍就會變成普通字符類型 無法自增操作.這將由字符串編碼格式?jīng)Q定.

字符串由多個字節(jié)組成,每個字節(jié)有 8bit.這樣的數(shù)據(jù)結(jié)構(gòu)還可以當(dāng)做 bitmap 去使用.

> set foo 1
OK
> get foo 
"1"
> incr foo
(integer) 2
> get foo
"2"

內(nèi)部原理

基本實現(xiàn)

上圖所示為字符串的基本結(jié)構(gòu),其中 content 里面保存的是字符串內(nèi)容,和 c 一樣用 0x\0作為結(jié)束字符.這個結(jié)束字符不會被計算len 中.代碼如下:

struct SDS{
  T capacity;		//數(shù)組容量
  T len;			//實際長度
  byte flages;	//標(biāo)志位,低三位表示類型
  byte[] content;	//數(shù)組內(nèi)容
}

可以看到 capacity和len 都是泛型,為什么不直接使用 int 呢?因為 Redis 內(nèi)部做了很多優(yōu)化,為了減少內(nèi)存的使用不同長度的字符串會使用不同的數(shù)據(jù)類型去表示.并且在創(chuàng)建字符串的時候 len 會和 capacity 一樣大,沒有冗余的空間,因為修改字符串的場景很少.(Redis 真的將內(nèi)存優(yōu)化到了極致)

編碼格式

Redis 字符串編碼格式有這么幾種:int 編碼、embstr編碼和raw 編碼 下面就詳細(xì)介紹下這幾種編碼的區(qū)別.

在這之前先要說說RedisObject. Redis 的對象頭,所有的 Redis 對象都有下面這個頭部結(jié)構(gòu).

struct RedisObject{
  int4 type;		//數(shù)據(jù)類型 5 種
  int4 encoding;	//鍵值內(nèi)部編碼格式 int 或 embstr 等等
  int24 lru;		// 當(dāng)內(nèi)存超限時采用LRU算法清除內(nèi)存中的對象
  
  int32 refcount;	//改鍵值被引用的數(shù)量
  void *ptr;		//對象內(nèi)容
}

int 編碼

當(dāng)儲存的值是64 位有符號整數(shù)類型的時候?qū)捎?int  編碼,這時可以使用鍵值自增操作.Redis 在啟動時會建立1w 個redisObject共享對象下文會講到,值在[0,1000)之間.如果存入整數(shù)的值在[0,1000)中Redis將不會創(chuàng)建新的對象,而是直接指向共享對象,鍵值不額外占用空間.

使用 object encoding命令可以查看編碼格式 使用 debug object命令可以查看更多信息

> set foo 1
OK
> object encoding foo
"int"
> set foo2 1
OK
> debug object foo
Value at:0x7f44b020aca0 refcount:2147483647 encoding:int serializedlength:2 lru:14691591 lru_seconds_idle:72588
> debug object foo2
Value at:0x7f44b020aca0 refcount:2147483647 encoding:int serializedlength:2 lru:14691591 lru_seconds_idle:72594

可以看到 foo 和 foo2  都在0x7f44b020aca0這里指向的是同一個對象

embstr 編碼

當(dāng)存儲的字符串長度較短時(len=44 字節(jié)),Redis將會采用 embstr 編碼.embstr 即embedded string 嵌入式的字符串.將SDS結(jié)構(gòu)體嵌入RedisObject對象中, 使用 malloc 方法一次分配內(nèi)存地址是連續(xù)的.

如圖所示:

raw 編碼

當(dāng)存儲的字符串長度較長時(len>44 字節(jié)),Redis 將會采用 raw 編碼,和 embstr 最大的區(qū)別就是 RedisObject 和 SDS 不在一起了,內(nèi)存地址不再連續(xù)了.

如圖所示:

思考

為什么字符串會有兩種格式 embstr 和格式和 raw分界線是 44 個字節(jié)?

Redis 默認(rèn)的內(nèi)存分配器jemalloc分配內(nèi)存大小的單位是次方,為了容納一個完整的 embstr 對象,最少會分配 32 字節(jié)的空間,再長些就是 64 字節(jié),再之后就認(rèn)為這是一個大字符串不適合用 embstr 存儲,而改用 raw 編碼了.

那么問題來了,64 字節(jié)的空間字符串長度是多少呢?答案就是 44 字節(jié).

下圖中 content 的長度為 45 字節(jié)減去結(jié)尾的 0x\0,就剩下 44 字節(jié)了.


總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • Redis緩存,泛型集合與json字符串的相互轉(zhuǎn)換實例
  • redis內(nèi)部數(shù)據(jù)結(jié)構(gòu)之SDS簡單動態(tài)字符串詳解
  • redis命令行查看中文不亂碼的方法(十六進(jìn)制字符串處理)
  • Redis字符串類型的常用命令小結(jié)
  • Redis中的動態(tài)字符串學(xué)習(xí)教程
  • Redis核心原理與實踐之字符串實現(xiàn)原理

標(biāo)簽:拉薩 伊春 河源 定州 泰州 甘南 畢節(jié) 南寧

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Redis字符串原理的深入理解》,本文關(guān)鍵詞  Redis,字符串,原理,的,深入,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Redis字符串原理的深入理解》相關(guān)的同類信息!
  • 本頁收集關(guān)于Redis字符串原理的深入理解的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章