前言
創(chuàng)新互聯(lián)建站10多年企業(yè)網(wǎng)站建設(shè)服務(wù);為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁設(shè)計(jì)及高端網(wǎng)站定制服務(wù),企業(yè)網(wǎng)站建設(shè)及推廣,對(duì)雨棚定制等多個(gè)領(lǐng)域擁有豐富的營銷推廣經(jīng)驗(yàn)的網(wǎng)站建設(shè)公司。
來掘進(jìn)都有兩年多了一直當(dāng)個(gè)小透明,今天終于發(fā)一次文章了.
最近在看 redis,感覺收獲很多,寫篇博客記錄一下.
Redis 有五種基礎(chǔ)數(shù)據(jù)結(jié)構(gòu):string,list,set,zset,hash.其中 string是最最最簡單的也是最常用的.這個(gè)數(shù)據(jù)類型雖然簡單但是內(nèi)部的結(jié)構(gòu)設(shè)計(jì)卻很是精致.
基本介紹
相比于 Java,在 Redis 中 string 是可以修改的,是動(dòng)態(tài)字符串(Simple Dynamic String 簡稱 SDS)他的內(nèi)部結(jié)構(gòu)更像是一個(gè) ArrayList,維護(hù)一個(gè)字節(jié)數(shù)組并預(yù)分配冗余空間以減少內(nèi)存的頻繁分配.當(dāng)字符串的長度小于 1MB時(shí),每次擴(kuò)容都是加倍現(xiàn)有的空間,如果字符串長度超過 1MB 時(shí),每次擴(kuò)容時(shí)只會(huì)擴(kuò)展 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 可以對(duì)多個(gè)字符串讀寫 節(jié)省網(wǎng)絡(luò)開銷
不僅如此redis 的字符串還可以用來儲(chǔ)存整數(shù)(更不像Java 的字符串了),并且可以自增操作.字符串保存整數(shù)類型的的范圍在 至
如果保存的數(shù)大于這個(gè)取值范圍就會(huì)變成普通字符類型 無法自增操作.這將由字符串編碼格式?jīng)Q定.
字符串由多個(gè)字節(jié)組成,每個(gè)字節(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)部原理
基本實(shí)現(xiàn)
上圖所示為字符串的基本結(jié)構(gòu),其中 content 里面保存的是字符串內(nèi)容,和 c 一樣用 0x\0作為結(jié)束字符.這個(gè)結(jié)束字符不會(huì)被計(jì)算len 中.代碼如下:
struct SDS{ T capacity; //數(shù)組容量 T len; //實(shí)際長度 byte flages; //標(biāo)志位,低三位表示類型 byte[] content; //數(shù)組內(nèi)容 }
可以看到 capacity和len 都是泛型,為什么不直接使用 int 呢?因?yàn)?Redis 內(nèi)部做了很多優(yōu)化,為了減少內(nèi)存的使用不同長度的字符串會(huì)使用不同的數(shù)據(jù)類型去表示.并且在創(chuàng)建字符串的時(shí)候 len 會(huì)和 capacity 一樣大,沒有冗余的空間,因?yàn)樾薷淖址膱鼍昂苌?(Redis 真的將內(nèi)存優(yōu)化到了極致)
編碼格式
Redis 字符串編碼格式有這么幾種:int 編碼、embstr編碼和raw 編碼 下面就詳細(xì)介紹下這幾種編碼的區(qū)別.
在這之前先要說說RedisObject. Redis 的對(duì)象頭,所有的 Redis 對(duì)象都有下面這個(gè)頭部結(jié)構(gòu).
struct RedisObject{ int4 type; //數(shù)據(jù)類型 5 種 int4 encoding; //鍵值內(nèi)部編碼格式 int 或 embstr 等等 int24 lru; // 當(dāng)內(nèi)存超限時(shí)采用LRU算法清除內(nèi)存中的對(duì)象 int32 refcount; //改鍵值被引用的數(shù)量 void *ptr; //對(duì)象內(nèi)容 }
int 編碼
當(dāng)儲(chǔ)存的值是64 位有符號(hào)整數(shù)類型的時(shí)候?qū)?huì)采用 int 編碼,這時(shí)可以使用鍵值自增操作.Redis 在啟動(dòng)時(shí)會(huì)建立1w 個(gè)redisObject共享對(duì)象下文會(huì)講到,值在[0,1000)之間.如果存入整數(shù)的值在[0,1000)中Redis將不會(huì)創(chuàng)建新的對(duì)象,而是直接指向共享對(duì)象,鍵值不額外占用空間.
使用 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這里指向的是同一個(gè)對(duì)象
embstr 編碼
當(dāng)存儲(chǔ)的字符串長度較短時(shí)(len<=44 字節(jié)),Redis將會(huì)采用 embstr 編碼.embstr 即embedded string 嵌入式的字符串.將SDS結(jié)構(gòu)體嵌入RedisObject對(duì)象中, 使用 malloc 方法一次分配內(nèi)存地址是連續(xù)的.
如圖所示:
raw 編碼
當(dāng)存儲(chǔ)的字符串長度較長時(shí)(len>44 字節(jié)),Redis 將會(huì)采用 raw 編碼,和 embstr 最大的區(qū)別就是 RedisObject 和 SDS 不在一起了,內(nèi)存地址不再連續(xù)了.
如圖所示:
思考
為什么字符串會(huì)有兩種格式 embstr 和格式和 raw分界線是 44 個(gè)字節(jié)?
Redis 默認(rèn)的內(nèi)存分配器jemalloc分配內(nèi)存大小的單位是次方,為了容納一個(gè)完整的 embstr 對(duì)象,最少會(huì)分配 32 字節(jié)的空間,再長些就是 64 字節(jié),再之后就認(rèn)為這是一個(gè)大字符串不適合用 embstr 存儲(chǔ),而改用 raw 編碼了.
那么問題來了,64 字節(jié)的空間字符串長度是多少呢?答案就是 44 字節(jié).
下圖中 content 的長度為 45 字節(jié)減去結(jié)尾的 0x\0,就剩下 44 字節(jié)了.
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)創(chuàng)新互聯(lián)的支持。
本文題目:Redis字符串原理的深入理解
地址分享:http://vcdvsql.cn/article38/gjigsp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊(cè)、網(wǎng)站收錄、網(wǎng)頁設(shè)計(jì)公司、建站公司、網(wǎng)站設(shè)計(jì)公司、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)