溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Redis數(shù)據(jù)結(jié)構(gòu)中的String類型有哪些

發(fā)布時間:2021-12-10 10:02:50 來源:億速云 閱讀:222 作者:iii 欄目:關(guān)系型數(shù)據(jù)庫

這篇文章主要介紹“Redis數(shù)據(jù)結(jié)構(gòu)中的String類型有哪些”,在日常操作中,相信很多人在Redis數(shù)據(jù)結(jié)構(gòu)中的String類型有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Redis數(shù)據(jù)結(jié)構(gòu)中的String類型有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

Redis數(shù)據(jù)結(jié)構(gòu)中的String類型有哪些

Redis常用作分布式KV緩存,很多人僅僅只會使用,卻不知道底層卻有著很多不為人知的秘密。

String類型

String作為Redis支持的最基礎(chǔ)的數(shù)據(jù)類型,首先我們來看下String,他的數(shù)據(jù)結(jié)構(gòu)和存儲是怎么樣的。

重新定義SDS 去存儲String

眾所周知,redis是用c語言進行編寫的,而c語言是沒有String類型的,只有char[],并且在初始化的是時候就必須大小指定類型后就不能改變。為了實現(xiàn)動態(tài)增加和擴展等功能,如incr命令,append命令,所以redis就自己定義維護了一個SDS(Simple Dynamic String)來實現(xiàn)這些功能。

我們先來看一下redis源碼中定義的數(shù)據(jù)結(jié)構(gòu),這里有5種類型,目的是為了節(jié)省空間。

Redis數(shù)據(jù)結(jié)構(gòu)中的String類型有哪些

1、len:獲取char[]的長度,需要遍歷數(shù)組,len(char[])時間復(fù)雜度O(n);
2、alloc:c語言沒有String類型, 只有char[],且char[]必須先分配空間長度,char[]預(yù)先分配了長度,數(shù)據(jù)增長后需要擴容;

3、falgs:總是占用一個字節(jié)。其中的最低3個bit用來表示header的類型。header的類型共有5種,在sds.h中有常量定義。
4、buf[]:c語言的char數(shù)組,用'\0'代表結(jié)束,意味著存儲二進制數(shù)據(jù)不能包含'\0',圖片音頻等用二進制存儲會有問題——這就是為什么Redis說自己實現(xiàn)的SDS是二進制安全的字符串。

SDS對c原始char數(shù)組的改進

1、Redis實現(xiàn)的SDS支持擴容
2、包含長度len,獲取長度復(fù)雜度O(1)
3、空間預(yù)分配
4、惰性空間釋放(下面會講)

SDS的優(yōu)缺點

優(yōu)點

  • 能夠支持擴容

  • 包含長度len,獲取長度復(fù)雜度O(1)

  • 空間預(yù)分配

缺點

  • 需要分配額外的內(nèi)存

  • 頻繁的分配和回收帶來的效率問題

Redis 使用的內(nèi)存分配庫 jemalloc

jemalloc 在分配內(nèi)存時,會根據(jù)我們申請的字節(jié)數(shù) N,找一個比 N 大,但是最接近 N 的 2 的冪次數(shù)作為分配的空間,這樣可以減少頻繁分配的次數(shù)。舉個例子。如果你申請 6 字節(jié)空間,jemalloc 實際會分配 8 字節(jié)空間;如果你申請 24 字節(jié)空間,jemalloc 則會分配 32 字節(jié)。所以,在我們剛剛說的場景里,dictEntry 結(jié)構(gòu)就占用了 32 字節(jié)。

空間預(yù)分配

空間預(yù)分配用于優(yōu)化 SDS 的字符串增長操作: 當(dāng) SDS 的 API 對一個 SDS 進行修改, 并且需要對 SDS 進行空間擴展的時候, 程序不僅會為 SDS 分配修改所必須要的空間, 還會為 SDS 分配額外的未使用空間。

其中, 額外分配的未使用空間數(shù)量由以下公式?jīng)Q定:

  • 如果對 SDS 進行修改之后, SDS 的長度(也即是 len 屬性的值)將小于 1 MB , 那么程序分配和 len 屬性同樣大小的未使用空間, 這時 SDS len 屬性的值將和 free 屬性的值相同。 舉個例子, 如果進行修改之后, SDS 的 len 將變成 13 字節(jié), 那么程序也會分配13 字節(jié)的未使用空間, SDS 的 buf 數(shù)組的實際長度將變成 13 + 13 + 1 = 27 字節(jié)(額外的一字節(jié)用于保存空字符)。

  • 如果對 SDS 進行修改之后, SDS 的長度將大于等于 1 MB , 那么程序會分配 1 MB 的未使用空間。 舉個例子, 如果進行修改之后, SDS 的 len 將變成 30 MB , 那么程序會分配 1 MB 的未使用空間, SDS 的 buf 數(shù)組的實際長度將為 30 MB + 1 MB + 1 byte 。

通過空間預(yù)分配策略, Redis 可以減少連續(xù)執(zhí)行字符串增長操作所需的內(nèi)存重分配次數(shù)。

惰性釋放

惰性空間釋放用于優(yōu)化 SDS 的字符串縮短操作: 當(dāng) SDS 的 API 需要縮短 SDS 保存的字符串時, 程序并不立即使用內(nèi)存重分配來回收縮短后多出來的字節(jié), 而是使用 free 屬性將這些字節(jié)的數(shù)量記錄起來, 并等待將來使用。

Redis的KV存儲結(jié)構(gòu)

在redis中,所有的存儲都是以KV鍵值對的形式存儲的,K是字符串類型,就是SDS;V 可能是字符串、list、hash等(Redis支持的數(shù)據(jù)結(jié)構(gòu)),V并沒有直接定成具體的類型,而是用redisObject封裝了一層;實際存儲的數(shù)據(jù)結(jié)構(gòu)是由ptr指針具體指向。

并且,redis為了更好的節(jié)省空間,ptr指針也有不同方式的存儲,一方面,當(dāng)保存的是 Long 類型整數(shù)時,RedisObject 中的指針就直接賦值為整數(shù)數(shù)據(jù)了,這樣就不用額外的指針再指向整數(shù)了,節(jié)省了指針的空間開銷。另一方面,當(dāng)保存的是字符串?dāng)?shù)據(jù),并且字符串小于等于 44 字節(jié)時,RedisObject 中的元數(shù)據(jù)、指針和 SDS 是一塊連續(xù)的內(nèi)存區(qū)域,這樣就可以避免內(nèi)存碎片。這種布局方式也被稱為 embstr 編碼方式。當(dāng)然,當(dāng)字符串大于 44 字節(jié)時,SDS 的數(shù)據(jù)量就開始變多了,Redis 就不再把 SDS 和 RedisObject 布局在一起了,而是會給 SDS 分配獨立的空間,并用指針指向 SDS 結(jié)構(gòu)。這種布局方式被稱為 raw 編碼模式。如圖所示

Redis數(shù)據(jù)結(jié)構(gòu)中的String類型有哪些

  • embstr 編碼
    存儲簡短字符串,一次的內(nèi)存分配;
    它是只讀的,如果對內(nèi)容進行修改,就會變成raw編碼(即使沒超過44字節(jié));

  • raw 編碼
    可分配多次內(nèi)存空間,存儲大于44個字節(jié)的長字符串。

raw 原生SDS 字符長度 縮減到小于44,會逆向變成embstr編碼嗎?
不會;Redis底層編碼,轉(zhuǎn)變后 不可逆(不會回退)。

到此,關(guān)于“Redis數(shù)據(jù)結(jié)構(gòu)中的String類型有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI