共計(jì) 2388 個(gè)字符,預(yù)計(jì)需要花費(fèi) 6 分鐘才能閱讀完成。
這篇文章主要介紹“Redis 數(shù)據(jù)結(jié)構(gòu)中的 String 類型有哪些”,在日常操作中,相信很多人在 Redis 數(shù)據(jù)結(jié)構(gòu)中的 String 類型有哪些問(wèn)題上存在疑惑,丸趣 TV 小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Redis 數(shù)據(jù)結(jié)構(gòu)中的 String 類型有哪些”的疑惑有所幫助!接下來(lái),請(qǐng)跟著丸趣 TV 小編一起來(lái)學(xué)習(xí)吧!
Redis 常用作分布式 KV 緩存,很多人僅僅只會(huì)使用,卻不知道底層卻有著很多不為人知的秘密。
String 類型
String 作為 Redis 支持的最基礎(chǔ)的數(shù)據(jù)類型,首先我們來(lái)看下 String,他的數(shù)據(jù)結(jié)構(gòu)和存儲(chǔ)是怎么樣的。
重新定義 SDS 去存儲(chǔ) String
眾所周知,redis 是用 c 語(yǔ)言進(jìn)行編寫的,而 c 語(yǔ)言是沒(méi)有 String 類型的,只有 char[],并且在初始化的是時(shí)候就必須大小指定類型后就不能改變。為了實(shí)現(xiàn)動(dòng)態(tài)增加和擴(kuò)展等功能,如 incr 命令,append 命令,所以 redis 就自己定義維護(hù)了一個(gè) SDS(Simple Dynamic String)來(lái)實(shí)現(xiàn)這些功能。
我們先來(lái)看一下 redis 源碼中定義的數(shù)據(jù)結(jié)構(gòu), 這里有 5 種類型,目的是為了節(jié)省空間。
1、len: 獲取 char[]的長(zhǎng)度,需要遍歷數(shù)組,len(char[])時(shí)間復(fù)雜度 O(n);
2、alloc:c 語(yǔ)言沒(méi)有 String 類型,只有 char[],且 char[]必須先分配空間長(zhǎng)度,char[]預(yù)先分配了長(zhǎng)度,數(shù)據(jù)增長(zhǎng)后需要擴(kuò)容;
3、falgs:總是占用一個(gè)字節(jié)。其中的最低 3 個(gè) bit 用來(lái)表示 header 的類型。header 的類型共有 5 種,在 sds.h 中有常量定義。
4、buf[]:c 語(yǔ)言的 char 數(shù)組,用 \0 代表結(jié)束,意味著存儲(chǔ)二進(jìn)制數(shù)據(jù)不能包含 \0,圖片音頻等用二進(jìn)制存儲(chǔ)會(huì)有問(wèn)題——這就是為什么 Redis 說(shuō)自己實(shí)現(xiàn)的 SDS 是二進(jìn)制安全的字符串。
SDS 對(duì) c 原始 char 數(shù)組的改進(jìn)
1、Redis 實(shí)現(xiàn)的 SDS 支持?jǐn)U容
2、包含長(zhǎng)度 len,獲取長(zhǎng)度復(fù)雜度 O(1)
3、空間預(yù)分配
4、惰性空間釋放(下面會(huì)講)
SDS 的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
能夠支持?jǐn)U容
包含長(zhǎng)度 len,獲取長(zhǎng)度復(fù)雜度 O(1)
空間預(yù)分配
缺點(diǎn)
需要分配額外的內(nèi)存
頻繁的分配和回收帶來(lái)的效率問(wèn)題
Redis 使用的內(nèi)存分配庫(kù) jemalloc
jemalloc 在分配內(nèi)存時(shí),會(huì)根據(jù)我們申請(qǐng)的字節(jié)數(shù) N,找一個(gè)比 N 大,但是最接近 N 的 2 的冪次數(shù)作為分配的空間,這樣可以減少頻繁分配的次數(shù)。舉個(gè)例子。如果你申請(qǐng) 6 字節(jié)空間,jemalloc 實(shí)際會(huì)分配 8 字節(jié)空間;如果你申請(qǐng) 24 字節(jié)空間,jemalloc 則會(huì)分配 32 字節(jié)。所以,在我們剛剛說(shuō)的場(chǎng)景里,dictEntry 結(jié)構(gòu)就占用了 32 字節(jié)。
空間預(yù)分配
空間預(yù)分配用于優(yōu)化 SDS 的字符串增長(zhǎng)操作:當(dāng) SDS 的 API 對(duì)一個(gè) SDS 進(jìn)行修改,并且需要對(duì) SDS 進(jìn)行空間擴(kuò)展的時(shí)候,程序不僅會(huì)為 SDS 分配修改所必須要的空間,還會(huì)為 SDS 分配額外的未使用空間。
其中,額外分配的未使用空間數(shù)量由以下公式?jīng)Q定:
如果對(duì) SDS 進(jìn)行修改之后,SDS 的長(zhǎng)度(也即是 len 屬性的值)將小于 1 MB,那么程序分配和 len 屬性同樣大小的未使用空間,這時(shí) SDS len 屬性的值將和 free 屬性的值相同。舉個(gè)例子,如果進(jìn)行修改之后,SDS 的 len 將變成 13 字節(jié),那么程序也會(huì)分配 13 字節(jié)的未使用空間,SDS 的 buf 數(shù)組的實(shí)際長(zhǎng)度將變成 13 + 13 + 1 = 27 字節(jié)(額外的一字節(jié)用于保存空字符)。
如果對(duì) SDS 進(jìn)行修改之后,SDS 的長(zhǎng)度將大于等于 1 MB,那么程序會(huì)分配 1 MB 的未使用空間。舉個(gè)例子,如果進(jìn)行修改之后,SDS 的 len 將變成 30 MB,那么程序會(huì)分配 1 MB 的未使用空間,SDS 的 buf 數(shù)組的實(shí)際長(zhǎng)度將為 30 MB + 1 MB + 1 byte。
通過(guò)空間預(yù)分配策略,Redis 可以減少連續(xù)執(zhí)行字符串增長(zhǎng)操作所需的內(nèi)存重分配次數(shù)。
惰性釋放
惰性空間釋放用于優(yōu)化 SDS 的字符串縮短操作:當(dāng) SDS 的 API 需要縮短 SDS 保存的字符串時(shí),程序并不立即使用內(nèi)存重分配來(lái)回收縮短后多出來(lái)的字節(jié),而是使用 free 屬性將這些字節(jié)的數(shù)量記錄起來(lái),并等待將來(lái)使用。
Redis 的 KV 存儲(chǔ)結(jié)構(gòu)
在 redis 中,所有的存儲(chǔ)都是以 KV 鍵值對(duì)的形式存儲(chǔ)的,K 是字符串類型,就是 SDS;V 可能是字符串、list、hash 等(Redis 支持的數(shù)據(jù)結(jié)構(gòu)),V 并沒(méi)有直接定成具體的類型,而是用 redisObject 封裝了一層;實(shí)際存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)是由 ptr 指針具體指向。
并且,redis 為了更好的節(jié)省空間,ptr 指針也有不同方式的存儲(chǔ),一方面,當(dāng)保存的是 Long 類型整數(shù)時(shí),RedisObject 中的指針就直接賦值為整數(shù)數(shù)據(jù)了,這樣就不用額外的指針再指向整數(shù)了,節(jié)省了指針的空間開(kāi)銷。另一方面,當(dāng)保存的是字符串?dāng)?shù)據(jù),并且字符串小于等于 44 字節(jié)時(shí),RedisObject 中的元數(shù)據(jù)、指針和 SDS 是一塊連續(xù)的內(nèi)存區(qū)域,這樣就可以避免內(nèi)存碎片。這種布局方式也被稱為 embstr 編碼方式。當(dāng)然,當(dāng)字符串大于 44 字節(jié)時(shí),SDS 的數(shù)據(jù)量就開(kāi)始變多了,Redis 就不再把 SDS 和 RedisObject 布局在一起了,而是會(huì)給 SDS 分配獨(dú)立的空間,并用指針指向 SDS 結(jié)構(gòu)。這種布局方式被稱為 raw 編碼模式。如圖所示
embstr 編碼
存儲(chǔ)簡(jiǎn)短字符串,一次的內(nèi)存分配;
它是只讀的,如果對(duì)內(nèi)容進(jìn)行修改,就會(huì)變成 raw 編碼(即使沒(méi)超過(guò) 44 字節(jié));
raw 編碼
可分配多次內(nèi)存空間,存儲(chǔ)大于 44 個(gè)字節(jié)的長(zhǎng)字符串。
raw 原生 SDS 字符長(zhǎng)度 縮減到小于 44,會(huì)逆向變成 embstr 編碼嗎?
不會(huì);Redis 底層編碼,轉(zhuǎn)變后 不可逆(不會(huì)回退)。
到此,關(guān)于“Redis 數(shù)據(jù)結(jié)構(gòu)中的 String 類型有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注丸趣 TV 網(wǎng)站,丸趣 TV 小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!