redis-對象系統(tǒng)

使用對象的好處:

    1. 在執(zhí)行命令之前,根據(jù)對象的類型來判斷一個對象是否可以執(zhí)行給定的命令叽讳。
  • 2.可以針對不同的使用場景寡喝,為對象設(shè)置多種不同的數(shù)據(jù)結(jié)構(gòu)實現(xiàn),從而優(yōu)化對象在不同場景下的使用效率历造。
  • 3.實現(xiàn)了基于引用計數(shù)技術(shù)的內(nèi)存回收機制。
  • 4.通過引用計數(shù)技術(shù)實現(xiàn)了對象共享機制,在適當(dāng)?shù)臈l件下帕膜,通過讓多個數(shù)據(jù)庫鍵來共享同一個對象來節(jié)約內(nèi)存枣氧。
  • 5.redis的對象帶有訪問時間記錄信息溢十,可以用于計算數(shù)據(jù)庫鍵的空轉(zhuǎn)時間垮刹。

1. 五種對象

字符串對象,列表對象张弛,哈希對象荒典,集合對象,有序集合對象吞鸭。

typedef struct redisObject
{
    // 類型
    unsigned type:4;

    // 編碼
    unsigned encoding:4;

    // 指向底層實現(xiàn)數(shù)據(jù)結(jié)構(gòu)的指針
    void *ptr;
    
} robj;

2 字符串對象(REDIS_STRING)

采用的編碼:REDIS_ENCODING_INT, REDIS_ENCODING_EMBSTR, REDIS_ENCODING_RAW

一個字符串對象保存的是整數(shù)值寺董,且可以用long類型來表示,那么編碼為int刻剥。如果保存的是一個字符串值遮咖,且長度大于39字節(jié),那么編碼為raw造虏。小于等于39字節(jié)御吞,編碼采用embstr。

2.1 raw和embstr的區(qū)別

raw和embstr都是使用redisobject結(jié)構(gòu)和sdshdr結(jié)構(gòu)(即SDS)來表示字符串對象漓藕,但raw編碼會調(diào)用兩次內(nèi)存分配函數(shù)來分別創(chuàng)建redisobject和sdshdr陶珠,而embstr編碼通過調(diào)用一次內(nèi)存分配函數(shù)來分配一塊連續(xù)的空間,空間中依次包含redisobject和sdshdr兩個結(jié)構(gòu)享钞。

用embstr編碼的字符串對象來保存短字符串值有以下好處:

  • embstr編碼將創(chuàng)建字符串對象所需的內(nèi)存分配次數(shù)從raw編碼的兩次降為一次揍诽。
  • 釋放embstr編碼的字符串對象只需要調(diào)用一次內(nèi)存釋放函數(shù),而釋放raw編碼的需要兩次栗竖。
  • 因為embstr編碼的字符串對象的所有數(shù)據(jù)都是保存在一塊連續(xù)的內(nèi)存里面暑脆,所以這種編碼的字符串對象比起raw編碼的字符串對象能夠更好的利用緩存帶來的優(yōu)勢。

2.2 編碼的轉(zhuǎn)換

int編碼的字符串對象狐肢,如果對對象執(zhí)行了一些命令添吗,使得它不再是整數(shù)值,那編碼就會從int變成raw处坪。

embstr編碼的字符串對象是只讀的根资。如果對embstr編碼的字符串對象做修改,那程序會先把對象的編碼從embstr轉(zhuǎn)換成raw同窘,然后再執(zhí)行修改命令玄帕。所以embstr的字符串對象執(zhí)行修改命令后,一定會變成一個raw編碼的字符串對象想邦。

3 列表對象(REDIS_LIST)

就是普通的list

采用的編碼:REDIS_ENCODING_ZIPLIST, REDIS_ENCODING_LINKEDLIST

代表命令:RPUSH,LPUSH,RPOP,LPOP,LLEN

ziplist編碼的列表對象使用壓縮列表作為底層實現(xiàn)裤纹。linkedlist使用雙端鏈表作為底層實現(xiàn)。

3.1 編碼轉(zhuǎn)換

  • 列表對象保存的所有字符串對象元素的長度都小于64字節(jié);
  • 列表對象保存的元素數(shù)量小于512個鹰椒。

當(dāng)列表對象可以同時滿足這上面兩個條件時锡移,列表對象使用ziplist編碼。否則漆际,使用linkedlist編碼淆珊。

4 哈希對象(REDIS_HASH)

就是類似于Java的map

采用的編碼:REDIS_ENCODING_ZIPLIST, REDIS_ENCODING_HT(hashtable)

當(dāng)采用了ziplist來保存編碼的時候,保存鍵的節(jié)點和保存值的節(jié)點一前一后在一起奸汇。

代表命令:HSET, HGET, HLEN

4.1 編碼轉(zhuǎn)換

  • 哈希對象保存的所有鍵值對的鍵和值的字符串對象元素的長度都小于64字節(jié)施符;
  • 哈希對象保存的元素數(shù)量小于512個。

當(dāng)哈希對象可以同時滿足這上面兩個條件時擂找,哈希對象使用ziplist編碼戳吝。否則,使用hashtable編碼贯涎。

5 集合對象(REDIS_SET)

類似于java的set

采用的編碼:REDIS_ENCODING_INTSET, REDIS_ENCODING_HT

代表命令:SADD, SPOP,SCARD

5.1 編碼轉(zhuǎn)換

  • 集合對象保存的所有元素都是整數(shù)值听哭;
  • 集合對象保存的元素數(shù)量小于512個。

當(dāng)集合對象可以同時滿足這上面兩個條件時塘雳,集合對象使用intset編碼陆盘。否則,使用hashtable編碼粉捻。

6 有序集合對象(REDIS_ZSET)

帶有分值(score)的set礁遣,在保存上是從小到大,有序的肩刃。

采用的編碼:REDIS_ENCODING_ZIPLIST, REDIS_ENCODING_SKIPLIST

當(dāng)采用了ziplist來保存編碼的時候祟霍,每個集合元素使用兩個緊挨在一起的壓縮列表節(jié)點來保存,第一個保存元素的成員盈包,而第二個元素則保存元素的分值沸呐。

代表命令:ZADD, ZCOUNT,ZCARD

6.1 skiplist編碼的有序集合對象實現(xiàn)

skiplist編碼的有序集合對象使用zset結(jié)構(gòu)作為底層實現(xiàn),一個zset結(jié)構(gòu)同時包含一個字典和一個跳躍表:

typedef struct zset
{

    zskiplist *zsl;

    dict *dict
} zset;

跳躍表和字典同時來保存有序集合元素呢燥,但這兩種數(shù)據(jù)結(jié)構(gòu)會通過指針來共享相同元素的成員和分值崭添。所以不會產(chǎn)生任何重復(fù)成員或者分值,也不會因此浪費內(nèi)存叛氨。

why?
因為使用字典呼渣,我們可以以O(shè)(1)復(fù)雜度查找成員的分值,但字典是無序的寞埠。使用跳躍表執(zhí)行范圍型操作的所有優(yōu)點就會保留下來屁置。所以redis采用兩種同時來實現(xiàn),可以讓有序集合的查找和范圍型操作都盡可能快的執(zhí)行仁连。

6.2 編碼轉(zhuǎn)換

  • 有序集合對象保存的所有元素成員的長度都小于64字節(jié)蓝角;
  • 有序集合對象保存的元素數(shù)量小于128個。

當(dāng)有序集合對象可以同時滿足這上面兩個條件時,有序集合對象使用ziplist編碼使鹅。否則揪阶,使用skiplist編碼。

7. 類型檢查與命令多態(tài)

redis用于操作鍵的命令基本可以分為兩種類型患朱,一種可以對任何類型的鍵執(zhí)行鲁僚,另一種只能對特定類型的鍵執(zhí)行。

7.1 類型檢查的實現(xiàn)

類型檢查通過redisobject的type屬性來實現(xiàn):

  • 在執(zhí)行一個特定類型的命令之前麦乞,服務(wù)器會先檢查輸入數(shù)據(jù)庫鍵的值對象是否為執(zhí)行命令所需類型蕴茴,如果是執(zhí)行劝评;
  • 否則姐直,拒絕執(zhí)行,并向客戶端返回一個類型錯誤蒋畜。

7.2 多態(tài)命令的實現(xiàn)

redis還會根據(jù)值對象的編碼方式声畏,選擇正確的命令實現(xiàn)代碼來執(zhí)行命令。

舉個例子:比如列表對象有ziplist和linkedlist兩種編碼可用姻成,前者使用壓縮列表api來實現(xiàn)列表命令插龄,后者使用雙端鏈表api來實現(xiàn)。這就是多態(tài)科展,只要執(zhí)行的是某個類型均牢,無論使用哪種編碼都可以正常執(zhí)行。

DEL, EXPIRE等命令也是多態(tài)才睹,基于類型的多態(tài)徘跪,一個命令可以同時處理多種不同類型的鍵;而LLEN等命令琅攘,基于編碼的多態(tài)垮庐,一個命令可以同時處理多種不同編碼。

8.內(nèi)存回收

引用計數(shù)技術(shù)實現(xiàn)的內(nèi)存回收機制坞琴。對象的整個生命周期可以分為創(chuàng)建對象哨查,操作對象,釋放對象三個階段剧辐。

typedef struct redisobject
{
    //...

    // 引用計數(shù)
    int refcount;

    //...   
} robj;
  • incrRefCount:將對象的引用計數(shù)值+1
  • decrRefCount:將對象的引用計數(shù)值-1寒亥,當(dāng)對象的引用計數(shù)值為0時,釋放對象荧关。
  • resetRefCount:將對象的引用計數(shù)值設(shè)置為0溉奕,但不釋放對象,這個函數(shù)通常在需要重新設(shè)置對象的引用計數(shù)值時使用羞酗。

9.對象共享

在redis中腐宋,讓多個鍵共享同一個值對象需要執(zhí)行以下兩個步驟:

  • 1.將數(shù)據(jù)庫鍵的指針指向一個現(xiàn)有的值對象;
  • 2.將被共享的值對象引用計數(shù)+1.
  • redis只對包含整數(shù)值的字符串對象進行共享(因為需要驗證是否相同,耗費cpu時間)胸竞。
  • 目前在初始化服務(wù)器時欺嗤,會創(chuàng)建一萬個字符串對象,包含了從0到9999的所有整數(shù)值卫枝。

10. 空轉(zhuǎn)時間

typedef struct redisobject
{
    //...

    // 記錄了對象最后一次被命令程序訪問的時間
    unsigned lru:22;

    //...   
} robj;

OBJECT IDLETIME 命令可以打印出給定鍵的空轉(zhuǎn)時長煎饼。這個命令在訪問鍵的值對象時,不會修改值對象的lru屬性校赤。

鍵的空轉(zhuǎn)時長還有一個作用:如果服務(wù)器打開了maxmemory選項吆玖,且回收算法是空轉(zhuǎn)時長,那么久利用這個屬性來回收內(nèi)存马篮,釋放空間沾乘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浑测,隨后出現(xiàn)的幾起案子翅阵,更是在濱河造成了極大的恐慌,老刑警劉巖迁央,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掷匠,死亡現(xiàn)場離奇詭異,居然都是意外死亡岖圈,警方通過查閱死者的電腦和手機讹语,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜂科,“玉大人顽决,你說我怎么就攤上這事〕缟悖” “怎么了擎值?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長逐抑。 經(jīng)常有香客問我鸠儿,道長,這世上最難降的妖魔是什么厕氨? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任进每,我火速辦了婚禮,結(jié)果婚禮上命斧,老公的妹妹穿的比我還像新娘田晚。我一直安慰自己,他們只是感情好国葬,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布贤徒。 她就那樣靜靜地躺著芹壕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪接奈。 梳的紋絲不亂的頭發(fā)上踢涌,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機與錄音序宦,去河邊找鬼睁壁。 笑死,一個胖子當(dāng)著我的面吹牛互捌,可吹牛的內(nèi)容都是我干的潘明。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼秕噪,長吁一口氣:“原來是場噩夢啊……” “哼钳降!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起巢价,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤牲阁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后壤躲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡备燃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年碉克,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片并齐。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡漏麦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出况褪,到底是詐尸還是另有隱情撕贞,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布测垛,位于F島的核電站捏膨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏食侮。R本人自食惡果不足惜号涯,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锯七。 院中可真熱鬧链快,春花似錦、人聲如沸眉尸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至霉祸,卻和暖如春炉峰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背脉执。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工疼阔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人半夷。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓婆廊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親巫橄。 傳聞我的和親對象是個殘疾皇子淘邻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容