日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

redis的zset的底层实现_Redis(三)--- Redis的五大数据类型的底层实现

發(fā)布時間:2023/12/9 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis的zset的底层实现_Redis(三)--- Redis的五大数据类型的底层实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1、簡介

Redis的五大數(shù)據(jù)類型也稱五大數(shù)據(jù)對象;前面介紹過6大數(shù)據(jù)結(jié)構(gòu),Redis并沒有直接使用這些結(jié)構(gòu)來實現(xiàn)鍵值對數(shù)據(jù)庫,而是使用這些結(jié)構(gòu)構(gòu)建了一個對象系統(tǒng)redisObject;這個對象系統(tǒng)包含了五大數(shù)據(jù)對象,字符串對象(string)、列表對象(list)、哈希對象(hash)、集合(set)對象和有序集合對象(zset);而這五大對象的底層數(shù)據(jù)編碼可以用命令OBJECT ENCODING來進行查看。

redisObject結(jié)構(gòu)

1 typedef structredisObject {2 //類型

3 unsigned type:4;4 //編碼

5 unsigned encoding:4;6 //指向底層實現(xiàn)數(shù)據(jù)結(jié)構(gòu)的指針

7 void *ptr;8 //...

9 } robj;

redis是以鍵值對存儲數(shù)據(jù)的,所以對象又分為鍵對象和值對象,即存儲一個key-value鍵值對會創(chuàng)建兩個對象,鍵對象和值對象。

鍵對象總是一個字符串對象,而值對象可以是五大對象中的任意一種。

type屬性存儲的是對象的類型,也就是我們說的?string、list、hash、set、zset中的一種,可以使用命令 TYPE key?來查看。

encoding屬性記錄了隊形所使用的編碼,即這個對象底層使用哪種數(shù)據(jù)結(jié)構(gòu)實現(xiàn)。

表中列出了底層編碼常量及對應(yīng)的OBJECT ENCODING?命令的輸出,前三項都是字符串結(jié)構(gòu)

我們在存入key-value鍵值對時并不會指定對象的encoding,而是Redis會根據(jù)不統(tǒng)的使用場景來為一個對象設(shè)置不同的編碼,可以達到節(jié)約內(nèi)存、加快訪問速度等目的。

2、字符串對象(string)

字符串對象底層數(shù)據(jù)結(jié)構(gòu)實現(xiàn)為簡單動態(tài)字符串(SDS)和直接存儲,但其編碼方式可以是int、raw或者embstr,區(qū)別在于內(nèi)存結(jié)構(gòu)的不同。

(1)int編碼

字符串保存的是整數(shù)值,并且這個正式可以用long類型來表示,那么其就會直接保存在redisObject的ptr屬性里,并將編碼設(shè)置為int,如圖:

(2)raw編碼

字符串保存的大于32字節(jié)的字符串值,則使用簡單動態(tài)字符串(SDS)結(jié)構(gòu),并將編碼設(shè)置為raw,此時內(nèi)存結(jié)構(gòu)與SDS結(jié)構(gòu)一致,內(nèi)存分配次數(shù)為兩次,創(chuàng)建redisObject對象和sdshdr結(jié)構(gòu),如圖:

(3)embstr編碼

字符串保存的小于等于32字節(jié)的字符串值,使用的也是簡單的動態(tài)字符串(SDS結(jié)構(gòu)),但是內(nèi)存結(jié)構(gòu)做了優(yōu)化,用于保存頓消的字符串;內(nèi)存分配也只需要一次就可完成,分配一塊連續(xù)的空間即可,如圖:

字符串對象總結(jié):

在Redis中,存儲long、double類型的浮點數(shù)是先轉(zhuǎn)換為字符串再進行存儲的。

raw與embstr編碼效果是相同的,不同在于內(nèi)存分配與釋放,raw兩次,embstr一次。

embstr內(nèi)存塊連續(xù),能更好的利用緩存在來的優(yōu)勢

int編碼和embstr編碼如果做追加字符串等操作,滿足條件下會被轉(zhuǎn)換為raw編碼;embstr編碼的對象是只讀的,一旦修改會先轉(zhuǎn)碼到raw。

3、列表對象(list)

列表對象的編碼可以是ziplist和linkedlist之一。

(1)?ziplist編碼

ziplist編碼的哈希隨想底層實現(xiàn)是壓縮列表,每個壓縮里列表節(jié)點保存了一個列表元素。

(2)linkedlist編碼

linkedlist編碼底層采用雙端鏈表實現(xiàn),每個雙端鏈表節(jié)點都保存了一個字符串對象,在每個字符串對象內(nèi)保存了一個列表元素。

列表對象編碼轉(zhuǎn)換:

列表對象使用ziplist編碼需要滿足兩個條件:一是所有字符串長度都小于64字節(jié),二是元素數(shù)量小于512,不滿足任意一個都會使用linkedlist編碼。

兩個條件的數(shù)字可以在Redis的配置文件中修改,list-max-ziplist-value選項和list-max-ziplist-entries選項。

圖中StringObject就是上一節(jié)講到的字符串對象,字符串對象是唯一個在五大對象中作為嵌套對象使用的。

4、哈希對象(hash)

哈希對象的編碼可以是ziplist和hashtable之一。

(1)ziplist編碼

ziplist編碼的哈希對象底層實現(xiàn)是壓縮列表,在ziplist編碼的哈希對象中,key-value鍵值對是以緊密相連的方式放入壓縮鏈表的,先把key放入表尾,再放入value;鍵值對總是向表尾添加。

(2)hashtable編碼

hashtable編碼的哈希對象底層實現(xiàn)是字典,哈希對象中的每個key-value對都使用一個字典鍵值對來保存。

字典鍵值對即是,字典的鍵和值都是字符串對象,字典的鍵保存key-value的key,字典的值保存key-value的value。

哈希對象編碼轉(zhuǎn)換:

哈希對象使用ziplist編碼需要滿足兩個條件:一是所有鍵值對的鍵和值的字符串長度都小于64字節(jié);二是鍵值對數(shù)量小于512個;不滿足任意一個都使用hashtable編碼。

以上兩個條件可以在Reids配置文件中修改hash-max-ziplist-value選項和hash-max-ziplist-entries選項。

5、集合對象(set)

集合對象的編碼可以是intset和hashtable之一。

(1)intset編碼

intset編碼的集合對象底層實現(xiàn)是整數(shù)集合,所有元素都保存在整數(shù)集合中。

(2)hashtable編碼

hashtable編碼的集合對象底層實現(xiàn)是字典,字典的每個鍵都是一個字符串對象,保存一個集合元素,不同的是字典的值都是NULL;可以參考java中的hashset結(jié)構(gòu)。

集合對象編碼轉(zhuǎn)換:

集合對象使用intset編碼需要滿足兩個條件:一是所有元素都是整數(shù)值;二是元素個數(shù)小于等于512個;不滿足任意一條都將使用hashtable編碼。

以上第二個條件可以在Redis配置文件中修改et-max-intset-entries選項。

6、有序集合對象(zset)

有序集合的編碼可以是ziplist和skiplist之一。

(1)ziplist編碼

ziplist編碼的有序集合對象底層實現(xiàn)是壓縮列表,其結(jié)構(gòu)與哈希對象類似,不同的是兩個緊密相連的壓縮列表節(jié)點,第一個保存元素的成員,第二個保存元素的分值,而且分值小的靠近表頭,大的靠近表尾。

(2)skiplist編碼

skiplist編碼的有序集合對象底層實現(xiàn)是跳躍表和字典兩種;

每個跳躍表節(jié)點都保存一個集合元素,并按分值從小到大排列;節(jié)點的object屬性保存了元素的成員,score屬性保存分值;

字典的每個鍵值對保存一個集合元素,字典的鍵保存元素的成員,字典的值保存分值。

為何skiplist編碼要同時使用跳躍表和字典實現(xiàn)?

跳躍表優(yōu)點是有序,但是查詢分值復(fù)雜度為O(logn);字典查詢分值復(fù)雜度為O(1) ,但是無序,所以結(jié)合連個結(jié)構(gòu)的有點進行實現(xiàn)。

雖然采用兩個結(jié)構(gòu)但是集合的元素成員和分值是共享的,兩種結(jié)構(gòu)通過指針指向同一地址,不會浪費內(nèi)存。

有序集合編碼轉(zhuǎn)換:

有序集合對象使用ziplist編碼需要滿足兩個條件:一是所有元素長度小于64字節(jié);二是元素個數(shù)小于128個;不滿足任意一條件將使用skiplist編碼。

以上兩個條件可以在Redis配置文件中修改zset-max-ziplist-entries選項和zset-max-ziplist-value選項。

7、總結(jié)

在Redis的五大數(shù)據(jù)對象中,string對象是唯一個可以被其他四種數(shù)據(jù)對象作為內(nèi)嵌對象的;

列表(list)、哈希(hash)、集合(set)、有序集合(zset)底層實現(xiàn)都用到了壓縮列表結(jié)構(gòu),并且使用壓縮列表結(jié)構(gòu)的條件都是在元素個數(shù)比較少、字節(jié)長度較短的情況下;

四種數(shù)據(jù)對象使用壓縮列表的優(yōu)點:

(1)節(jié)約內(nèi)存,減少內(nèi)存開銷,Redis是內(nèi)存型數(shù)據(jù)庫,所以一定情況下減少內(nèi)存開銷是非常有必要的。

(2)減少內(nèi)存碎片,壓縮列表的內(nèi)存塊是連續(xù)的,并分配內(nèi)存的次數(shù)一次即可。

(3)壓縮列表的新增、刪除、查找操作的平均時間復(fù)雜度是O(N),在N再一定的范圍內(nèi),這個時間幾乎是可以忽略的,并且N的上限值是可以配置的。

(4)四種數(shù)據(jù)對象都有兩種編碼結(jié)構(gòu),靈活性增加。

參考:

《Redis設(shè)計與實現(xiàn)》黃健宏著,網(wǎng)上對Redis的詳解等

此博客為筆者使用redis很久之后,參考網(wǎng)絡(luò)上各類文章總結(jié)性書寫,原創(chuàng)手打,如有錯誤歡迎指正。

總結(jié)

以上是生活随笔為你收集整理的redis的zset的底层实现_Redis(三)--- Redis的五大数据类型的底层实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。