Redis對象

Redis是基于上一篇文章所說的數(shù)據(jù)結(jié)構(gòu)創(chuàng)建了一個對象系統(tǒng),這個系統(tǒng)包含字符串對象残黑、列表對象撇吞、哈希對象、集合對象和有序集合對象這五種類型的對象魄健。

Redis的對象系統(tǒng)還實現(xiàn)了基于引用技術(shù)技術(shù)的內(nèi)存回收機(jī)制,當(dāng)程序不在使用某個對象的時候插勤,這個對象所占用的內(nèi)存就會被自動釋放沽瘦。

對象的類型和編碼

對象結(jié)構(gòu)

typedef struct redisObject {
    //類型
    unsigned type:4;
    //編碼
    unsigned encoding:4;
    //指向底層實現(xiàn)數(shù)據(jù)結(jié)構(gòu)的指針
    void *ptr;
    //
    ...
}robj;

類型

對象的type屬性記錄了對象的類型农尖,值是五種基礎(chǔ)對象之一析恋。

對于Redis數(shù)據(jù)庫保存對的鍵值對來說,鍵總是一個字符串對象盛卡,而值可以是字符串對象助隧、列表對象、哈希對象窟扑、集合對象或者有序集合對象的其中一種喇颁。

對象 對象 type 屬性的值 TYPE 命令的輸出
字符串對象 REDIS_STRING "string"
列表對象 REDIS_LIST "list"
哈希對象 REDIS_HASH "hash"
集合對象 REDIS_SET "set"
有序集合對象 REDIS_ZSET "zset"

使用Type命令可以返回數(shù)據(jù)庫鍵對應(yīng)的值對象的類型:

#鍵為字符串對象,值為字符串對象
redis> SET msg "hello world"
OK
redis> TYPE msg
string

#鍵為字符串對象嚎货,值為列表對象
redis>RPUSH numbers 1 3 5
(integer) 6

redis>TYPE numbers
list
·····

編碼和底層實現(xiàn)

對象的ptr指針指向?qū)ο蟮牡讓訉崿F(xiàn)數(shù)據(jù)結(jié)構(gòu)橘霎,而這些數(shù)據(jù)結(jié)構(gòu)由對象的encoding屬性決定。

encoding屬性記錄了對象所使用的編碼殖属,也即是說這個對象使用了什么數(shù)據(jù)結(jié)構(gòu)作為對象的底層實現(xiàn)姐叁。

每種類型的對象都至少使用了兩種不同的編碼。

類型 編碼 對象
REDIS_STRING REDIS_ENCODING_INT 使用整數(shù)值實現(xiàn)的字符串對象洗显。
REDIS_STRING REDIS_ENCODING_EMBSTR 使用 embstr 編碼的簡單動態(tài)字符串實現(xiàn)的字符串對象外潜。
REDIS_STRING REDIS_ENCODING_RAW 使用簡單動態(tài)字符串實現(xiàn)的字符串對象。
REDIS_LIST REDIS_ENCODING_ZIPLIST 使用壓縮列表實現(xiàn)的列表對象挠唆。
REDIS_LIST REDIS_ENCODING_LINKEDLIST 使用雙端鏈表實現(xiàn)的列表對象处窥。
REDIS_HASH REDIS_ENCODING_ZIPLIST 使用壓縮列表實現(xiàn)的哈希對象。
REDIS_HASH REDIS_ENCODING_HT 使用字典實現(xiàn)的哈希對象玄组。
REDIS_SET REDIS_ENCODING_INTSET 使用整數(shù)集合實現(xiàn)的集合對象滔驾。
REDIS_SET REDIS_ENCODING_HT 使用字典實現(xiàn)的集合對象谒麦。
REDIS_ZSET REDIS_ENCODING_ZIPLIST 使用壓縮列表實現(xiàn)的有序集合對象。
REDIS_ZSET REDIS_ENCODING_SKIPLIST 使用跳躍表和字典實現(xiàn)的有序集合對象哆致。

使用 OBJECT ENCODING 命令可以查看一個數(shù)據(jù)庫鍵的值對象的編碼:

redis> SET msg "hello wordl"
OK

redis> OBJECT ENCODING msg
"embstr"

redis> SET story "long long long long long long ago ..."
OK

redis> OBJECT ENCODING story
"raw"

redis> SADD numbers 1 3 5
(integer) 3

redis> OBJECT ENCODING numbers
"intset"
····

字符串對象

字符串對象的編碼可以是int绕德、raw或者embstr

如果一個字符串對象保存的是整數(shù)值,并且這個整數(shù)值可以用long類型來表示摊阀,那么字符串對象會將整數(shù)值保存在字符串對象結(jié)構(gòu)的ptr屬性里面耻蛇。

如果字符串對象保存的是一個字符串值,并且這個字符串值的長度大于32字節(jié)胞此,那么字符串對象將使用一個簡單動態(tài)字符串(SDS)來保存這個字符串值臣咖,并將對象的編碼設(shè)置為raw

如果字符串對象保存的是一個字符串值豌鹤,并且這個字符串值的長度小于等于32字節(jié)亡哄,那么字符串對象將使用embstr編碼的方式來保存這個字符串值。

embstr編碼是專門用于和保存短字符串的一種優(yōu)化編碼方式布疙,這種編碼和raw編碼一樣,都是用redisObject結(jié)構(gòu)和sdshdr結(jié)構(gòu)來表示字符串對象愿卸,但raw編碼會調(diào)用兩次內(nèi)存分配函數(shù)來分別創(chuàng)建redisObject結(jié)構(gòu)和sdshdr結(jié)構(gòu)灵临,而embstr編碼則通過調(diào)用一次內(nèi)存分配函數(shù)來分配一塊連續(xù)的空間,空間中依次包含redisObject和sdshdr兩個結(jié)構(gòu)趴荸。


列表對象

列表對象的編碼可以是ziplist或者linkedlist儒溉。

ziplist編碼的列表對象使用壓縮列表作為底層實現(xiàn),每個壓縮列表節(jié)點(entry)保存了一個列表元素发钝。

linkedlist編碼的列表對象使用雙端鏈表作為底層實現(xiàn)顿涣,每個雙端鏈表節(jié)點(node)都保存了一個字符串對象,而每個字符串對象都保存了一個列表元素酝豪。

linkdedlist編碼的列表對象在底層的雙端鏈表結(jié)構(gòu)中包含了多個字符串對象涛碑,這種嵌套字符串對象的行為在哈希對象、集合對象和有序結(jié)合對象中都會出現(xiàn)孵淘,字符串對象是Redis五種類型的對象中唯一一種會被其它四中類型對象嵌套的對象蒲障。


哈希對象

哈希對象的編碼可以是ziplist或者h(yuǎn)ashtable。

ziplist編碼的哈希對象使用壓縮列表作為底層實現(xiàn)瘫证,每當(dāng)有新的鍵值對要加入到哈希對象時揉阎,程序會先將保存了鍵的壓縮列表節(jié)點推入到壓縮列表表尾,然后再將保存了值的壓縮列表節(jié)點推入到壓縮列表表尾背捌。

hashtable編碼的哈希對象使用了字典作為底層實現(xiàn)毙籽,哈希對象中的每個鍵值對都使用一個字典鍵值對來保存:

  • 字典的每個鍵都是一個字符串對象,對象中保存了鍵值對的鍵毡庆;
  • 字典的每個值都是一個字符串對象坑赡,對象中保存了鍵值對的值烙如。

集合對象

結(jié)合對象的編碼可以是intset或者h(yuǎn)ashtable。

intset編碼的集合對象使用整數(shù)集合作為底層實現(xiàn)垮衷,集合對象包含的所有元素都被保存在整數(shù)集合里面厅翔。

hashtable編碼的集合對象使用字典作為底層實現(xiàn),字典的每個鍵都是一個字符串對象搀突,每個字符串對象包含了一個集合元素刀闷,而字典的值則全部被設(shè)置為NULL。


有序集合對象

有序集合的編碼可以是ziplist或者skiplist仰迁。

ziplist編碼的壓縮列表對象使用壓縮列表作為底層實現(xiàn)甸昏,每個集合元素使用兩個緊挨在一起的壓縮列表節(jié)點來保存,第一個節(jié)點保存元素的成員(member)徐许,而第二個元素則保存元素的分值(score)施蜜。

壓縮列表內(nèi)的集合元素按分值從小到大進(jìn)行排序,分值較小的元素被放置在靠近表頭的位置雌隅,而分值較大的元素則被放置在靠近表尾的方向翻默。

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

typedef struct zset{
    zskiplist *zsl;
    dict *dict;
}zset;

zset結(jié)構(gòu)中的zsl跳躍表按分值從小到大保存了所有集合元素恰起,每個跳躍表節(jié)點都保存了一個集合元素:跳躍表節(jié)點的object屬性保存了元素的成員修械,而跳躍表節(jié)點的score屬性則保存了元素的分值。

通過這個跳躍表检盼,程序可以對有序集合進(jìn)行范圍型操作肯污。、

除此之外吨枉,zset結(jié)構(gòu)中的dict字典為有序集合創(chuàng)建了一個從成員到分值的映射蹦渣,字典中的每個鍵值對都保存了一個集合元素:字典的鍵保存了元素的成員,而字典的值則保存了元素的分值貌亭。

通過這個字典柬唯,程序可以用O(1)復(fù)雜度查找給定成員的分值。

zset結(jié)構(gòu)同時使用跳躍表和字典來保存有序集合元素属提,但這兩種數(shù)據(jù)結(jié)構(gòu)都會通過指針來共享相同元素的成員和分值权逗,所以同時使用跳躍表和字典來保存集合元素不會產(chǎn)生任何重復(fù)成員或者分值,也不會因此而浪費額外的內(nèi)存冤议。


編碼與轉(zhuǎn)換

在每一種對象中斟薇,都會存在編碼和轉(zhuǎn)換,個人的理解是在滿足特定條件下恕酸,對象底層的編碼方式會從這種轉(zhuǎn)換為另一種堪滨。

舉些例子:

字符串對象中:
int編碼的字符串對象和embstr編碼的字符串對象在條件滿足的情況下,會被轉(zhuǎn)換成raw編碼的字符串對象蕊温。

如果通過APPEND命令袱箱,向一個保存了整數(shù)值的字符串對象追加了一個字符串值遏乔,因為追加操作只能對字符串值執(zhí)行,所以程序會先將之前保存的整數(shù)值轉(zhuǎn)換成字符串值发笔,然后再執(zhí)行追加操作盟萨,操作的執(zhí)行結(jié)果就是一個raw編碼的保存了字符串值的字符串對象。

哈希對象中:
當(dāng)哈希對象可以同時滿足以下兩個條件時了讨,哈希對象使用ziplist編碼:

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

不能滿足這兩個條件的哈希對象需要使用hashtable編碼前计;


還有關(guān)于每個對象API在上一篇文章講過胞谭,根據(jù)每個對象的特性,用于保存相應(yīng)的數(shù)據(jù)上男杈。

Redis還有很多需要學(xué)習(xí)丈屹,關(guān)于單機(jī)和集群、事務(wù)伶棒、持久化等都還沒了解到旺垒,但是底層了解之后就是用于實戰(zhàn),下一篇文章將會在實際項目中使用Redis

Redis學(xué)習(xí)地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肤无,一起剝皮案震驚了整個濱河市袖牙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舅锄,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件司忱,死亡現(xiàn)場離奇詭異皇忿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)坦仍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門鳍烁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人繁扎,你說我怎么就攤上這事幔荒。” “怎么了梳玫?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵爹梁,是天一觀的道長。 經(jīng)常有香客問我提澎,道長姚垃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任盼忌,我火速辦了婚禮积糯,結(jié)果婚禮上掂墓,老公的妹妹穿的比我還像新娘。我一直安慰自己看成,他們只是感情好君编,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著川慌,像睡著了一般吃嘿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窘游,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天唠椭,我揣著相機(jī)與錄音,去河邊找鬼忍饰。 笑死贪嫂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的艾蓝。 我是一名探鬼主播力崇,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赢织!你這毒婦竟也來了亮靴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤于置,失蹤者是張志新(化名)和其女友劉穎茧吊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體八毯,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡搓侄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了话速。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讶踪。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖泊交,靈堂內(nèi)的尸體忽然破棺而出乳讥,到底是詐尸還是另有隱情,我是刑警寧澤廓俭,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布云石,位于F島的核電站,受9級特大地震影響白指,放射性物質(zhì)發(fā)生泄漏留晚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望错维。 院中可真熱鬧奖地,春花似錦、人聲如沸赋焕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隆判。三九已至犬庇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間侨嘀,已是汗流浹背臭挽。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留咬腕,地道東北人欢峰。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像涨共,于是被迫代替她去往敵國和親纽帖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

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

  • 上周看完Redis設(shè)計與實現(xiàn)举反,過程結(jié)合Redis的unstable分支的源碼來對照懊直,基本對Redis的實現(xiàn)原理有了...
    zcliu閱讀 1,025評論 0 1
  • 1. 對象類型與編碼 Redis的對象由redisObject結(jié)構(gòu)表示: type屬性表示對象的類型: encod...
    童伯虎閱讀 529評論 0 0
  • 本文為筆者對在學(xué)習(xí)Redis過程中所收集資料的一個總結(jié),目的是為了以后方便回顧相關(guān)的知識,大部分為非原創(chuàng)內(nèi)容火鼻。特此...
    EakonZhao閱讀 14,414評論 0 9
  • 天未亮就出發(fā),飛機(jī)晚點蛾默,等了很久,終于在黑夜來臨之前捉貌,到了異國他鄉(xiāng)的德里支鸡,在趕往古爾岡的路上,看到鄉(xiāng)村道路趁窃,聚集的...
    巴拿馬草帽閱讀 595評論 1 0
  • 最近剛開始準(zhǔn)備托福牧挣,休息時練練吉他畫畫圖。下周就要開學(xué)了醒陆,發(fā)現(xiàn)自己不會同時地每日地多線程完成多項任務(wù)瀑构。有時候一件事...
    JoyeaC閱讀 7,010評論 0 12