Redis對象(三) - 其它特性

類型檢查和多態(tài)命令的實(shí)現(xiàn)

redis中用于鍵操作的命令基本上可以分為兩類:

  1. 可以對任何類型的鍵執(zhí)行, eg. del, expire, rename, type, object

  2. 只能對特定命令執(zhí)行的鍵,

    eg. set瞳筏、get腥例、appendstrlen 等命令只能對字符串鍵執(zhí)行

    ? hdelhsethgethlen 等命令只能對hash鍵執(zhí)行

    ? rpush虐先、lpoplinsert派敷、llen等只能對列表鍵執(zhí)行

    ? sadd蛹批、spopsinter篮愉、scard等命令只能對集合鍵執(zhí)行

    ? zadd腐芍、zcardzrank试躏、zcore 等命令只能對有序集合鍵執(zhí)行

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

類型特定命令所進(jìn)行的類型檢查是通過redisObject結(jié)構(gòu)的type屬性 來實(shí)現(xiàn)的.

  1. 在執(zhí)行一個(gè)類型特定命令之前, 服務(wù)器先檢查輸入數(shù)據(jù)庫鍵的值對象是否為執(zhí)行命令所需要的類型, 是猪勇、就執(zhí)行
  2. 否則, server拒絕執(zhí)行、并向client返回一個(gè)類型錯(cuò)誤

eg. 對于llen命令:

在執(zhí)行l(wèi)len命令前冗酿、server會(huì)先檢查輸入數(shù)據(jù)庫鍵的值對象是否為列表類型, 即: 檢查redisObjecttype屬性是否為redis_list, 是的話埠对、執(zhí)行 llen命令, 否則返回類型錯(cuò)誤

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

Redis除了會(huì)根據(jù)值對象的類型來判斷是否能執(zhí)行特定命令外络断、還會(huì)根據(jù)值對象的編碼方式裁替、選擇正確的命令實(shí)現(xiàn)代碼來執(zhí)行命令

eg. 對一個(gè)鍵執(zhí)行 llen命令, 則服務(wù)器除了要確保執(zhí)行命令的是列表鍵之外, 還要根據(jù)鍵的值對象所使用的編碼來選擇正確的llen命令實(shí)現(xiàn)

  1. 若列表對象的編碼為 ziplist, 那么說明列表對象的實(shí)現(xiàn)為壓縮列表, 程序?qū)⑹褂?ziplistLen 函數(shù)來返回列表的長度
  2. 若列表對象的編碼為 linkedlist, 說明列表對象的實(shí)現(xiàn)為雙端鏈表, 程序?qū)⑹褂?listLength 函數(shù)來返回列表的長度

借用面向?qū)ο蟮男g(shù)語來說、可以認(rèn)為llen命令的實(shí)現(xiàn)是多態(tài)的, 只要執(zhí)行 llen 命令的是列表鍵貌笨、無論值對象是 ziplist 還是 linkedlist 編碼弱判、命令都可以正常執(zhí)行

delexpire等命令和llen命令的區(qū)別在于锥惋、前者是基于類型的多態(tài), 一個(gè)命令可以同時(shí)處理多種不同類型的鍵昌腰、而后者是基于編碼的多態(tài): 一個(gè)命令可以同時(shí)用于處理多種不同的編碼

內(nèi)存回收

因?yàn)镃語言并不具備內(nèi)存回收功能, redis 在自己的對象系統(tǒng)中構(gòu)建了一個(gè)引用計(jì)數(shù)(reference counting) 技術(shù)來實(shí)現(xiàn)內(nèi)存回收機(jī)制, 通過引用計(jì)數(shù)機(jī)制开伏、程序可以通過跟蹤對象的引用計(jì)數(shù)信息、在適當(dāng)?shù)臅r(shí)候自動(dòng)釋放對象并進(jìn)行內(nèi)存回收

每個(gè)對象的引用計(jì)數(shù)信息由 RedisObject 結(jié)構(gòu)的 refcount屬性記錄:

typedef struct redisObject {
  // ...
  int refcount; // 引用計(jì)數(shù)
  // ...
} robj;

對象的引用技術(shù)信息會(huì)隨著對象的使用狀態(tài)不斷變化

  1. 創(chuàng)建一個(gè)新的對象時(shí)遭商、引用計(jì)數(shù)初始化為1
  2. 對象被一個(gè)新的程序引用時(shí)固灵、引用計(jì)數(shù)值 +1
  3. 對象不再被一個(gè)程序引用時(shí)、引用計(jì)數(shù)值 -1
  4. 對象的引用計(jì)數(shù)值變?yōu)?時(shí)劫流、對象所占用的內(nèi)存會(huì)被釋放

下邊是修改對象引用計(jì)數(shù)的API

函數(shù) 作用
incrRefCount 將對象的引用計(jì)數(shù)值+1
decrRefCount 將對象的引用計(jì)數(shù)值-1, 當(dāng)對象的引用計(jì)數(shù)值=0時(shí)巫玻、釋放對象
resetRefCount 將對象的引用計(jì)數(shù)值設(shè)為0, 但不釋放對象、需要重設(shè)對象引用值是使用

其它不同類型的對象也會(huì)經(jīng)歷類似的過程

共享對象

除了實(shí)現(xiàn)引用計(jì)數(shù)內(nèi)存回收機(jī)制外祠汇、對象的引用計(jì)數(shù)屬性還帶有對象共享的作用.

eg. A鍵創(chuàng)建了一個(gè)包含整數(shù)值100的字符串對象作為值對象, 此時(shí)若B鍵也想要?jiǎng)?chuàng)建一個(gè)同樣保存了整數(shù)值100的字符串對象作為值對象仍秤、那么Server有兩種做法:

  1. 為鍵B創(chuàng)建一個(gè)包含整數(shù)值100的字符串對象
  2. 讓鍵A和鍵B共享同一個(gè)字符串對象

明顯, 第二種方式更節(jié)約內(nèi)存, 在Redis中、多個(gè)鍵共享同一個(gè)值需要執(zhí)行以下步驟:

  • 將數(shù)據(jù)庫鍵的值指向一個(gè)現(xiàn)有的值對象
  • 將被共享的值對象的引用計(jì)數(shù)+1

**注意: **

創(chuàng)建共享字符串對象的數(shù)量可以通過修改 redis.h/redis_shared_integers 常量來修改

eg, 創(chuàng)建一個(gè)值為100的鍵a, 使用object refcount 命令查看a的引用計(jì)數(shù), 會(huì)發(fā)現(xiàn)值為2

redis> set a 100
OK
redis> object refcount a
(integer) 2

引用這個(gè)值對象的兩個(gè)程序分表是持有這個(gè)值對象的服務(wù)器程序, 及共享這個(gè)值對象的鍵A

另外: 這些共享對象不單單只有字符串鍵可以使用, 那些在數(shù)據(jù)結(jié)構(gòu)中嵌套了字符串對象的對象(linkedlist編碼的列表對象可很、hashtable編碼的hash對象诗力、hashtable編碼的集合對象及zset編碼的有序集合對象)等都可以使用這些共享對象

思考

為什么redis不共享包含字符串的對象?

當(dāng)服務(wù)器考慮將一個(gè)共享對象設(shè)置為鍵的值對象時(shí)、程序需要檢查給定的共享對象和鍵想創(chuàng)建的目標(biāo)對象是否完全相同, 只有在共享對象和目標(biāo)對象完全相同的情況下我抠、程輝才會(huì)將共享對象的用作鍵的值對象苇本、而一個(gè)共享對象保存的值越復(fù)雜、驗(yàn)證兩者相同的復(fù)雜度就會(huì)越高, 消耗的CPU時(shí)間也會(huì)越多

  • 若共享對象保存整數(shù)值的字符串對象屿良、那么驗(yàn)證操作的復(fù)雜度為 O(1)
  • 若共享對象是保存字符串值的字符串對象圈澈、那么驗(yàn)證操作的復(fù)雜度為 O(N)
  • 若共享對象是包含了多個(gè)值(或者對象)的對象, 比如列表對象或者h(yuǎn)ash對象、驗(yàn)證的復(fù)雜度將是O(N2)

因此尘惧、盡管共享更復(fù)雜的對象可以節(jié)約更多內(nèi)存康栈、但受到CPU時(shí)間的限制、redis只對包含整數(shù)值的字符串對象進(jìn)行共享

對象的空轉(zhuǎn)時(shí)長

除了前邊介紹過的type喷橙、encoding啥么、ptrrefcount 4個(gè)屬性外, redisObject結(jié)構(gòu)包含的最后一個(gè)屬性為 lru屬性, 它記錄了對象最后一次被命令訪問的時(shí)間

typedef struct redisObject {
  // ...
  unsigned lru:22;
  // ...
} robj;

object idletime 命令可以打印出給定鍵的空轉(zhuǎn)時(shí)長, 就是通過當(dāng)前時(shí)間 - 鍵的lru時(shí)間得到的

注意:

Object idletime的實(shí)現(xiàn)是特殊的, 它在訪問鍵的時(shí)候、不會(huì)修改值對象的lru屬性

除了使用 命令打印鍵的空轉(zhuǎn)時(shí)長, lru屬性還用于回收內(nèi)存, 當(dāng)設(shè)置了 maxmemory 選項(xiàng), 且服務(wù)器用于回收內(nèi)存的算法為 volatile-lru 或者 allkeys-lru 時(shí)贰逾、當(dāng)服務(wù)器占用內(nèi)存超過了 maxmemory設(shè)置的上限值時(shí), 空轉(zhuǎn)時(shí)長較高的鍵會(huì)優(yōu)先被服務(wù)器釋放.

重點(diǎn)回顧

  1. redis數(shù)據(jù)庫的中每個(gè)鍵值對的鍵和值都是一個(gè)對象
  2. redis共有字符串悬荣、列表、hash疙剑、結(jié)合氯迂、有序集合五種類型的對象, 每種類型的對象至少有2種或以上的編碼方式, 不同的編碼可以在不同的場景上優(yōu)化對象的使用概率
  3. 服務(wù)器在執(zhí)行某些命令之前、會(huì)先檢查給定鍵的類型能否執(zhí)行
  4. redis的對象系統(tǒng)帶有引用計(jì)數(shù)實(shí)現(xiàn)的內(nèi)存回收機(jī)制, 當(dāng)一個(gè)對象不再被使用時(shí)言缤、該對象占用的內(nèi)存會(huì)被自動(dòng)釋放
  5. redis會(huì)共享值為 0 到 9999 的字符串對象
  6. 對象會(huì)記錄自己最后一次被訪問的時(shí)間, 這個(gè)時(shí)間還可以用于計(jì)算對象的空轉(zhuǎn)時(shí)長
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嚼蚀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子管挟,更是在濱河造成了極大的恐慌轿曙,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異导帝,居然都是意外死亡守谓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門您单,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斋荞,“玉大人,你說我怎么就攤上這事虐秦∑┟ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵羡疗,是天一觀的道長染服。 經(jīng)常有香客問我,道長叨恨,這世上最難降的妖魔是什么柳刮? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮痒钝,結(jié)果婚禮上秉颗,老公的妹妹穿的比我還像新娘。我一直安慰自己送矩,他們只是感情好蚕甥,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著栋荸,像睡著了一般菇怀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晌块,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天爱沟,我揣著相機(jī)與錄音,去河邊找鬼匆背。 笑死呼伸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钝尸。 我是一名探鬼主播括享,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼珍促!你這毒婦竟也來了铃辖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤踢星,失蹤者是張志新(化名)和其女友劉穎澳叉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沐悦,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡成洗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了藏否。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓶殃。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖副签,靈堂內(nèi)的尸體忽然破棺而出遥椿,到底是詐尸還是另有隱情,我是刑警寧澤淆储,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布冠场,位于F島的核電站,受9級特大地震影響本砰,放射性物質(zhì)發(fā)生泄漏碴裙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一点额、第九天 我趴在偏房一處隱蔽的房頂上張望舔株。 院中可真熱鬧,春花似錦还棱、人聲如沸载慈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽办铡。三九已至,卻和暖如春琳要,著一層夾襖步出監(jiān)牢的瞬間料扰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工焙蹭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晒杈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓孔厉,卻偏偏與公主長得像拯钻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子撰豺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

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

  • 對象 當(dāng)稱呼一個(gè)數(shù)據(jù)庫鍵為"字符串鍵"粪般、"列表鍵"時(shí),指的是這個(gè)鍵對應(yīng)的值為"字符串對象"污桦、"列表對象"亩歹。 Red...
    xMustang閱讀 273評論 0 0
  • Redis的內(nèi)存優(yōu)化 聲明:本文內(nèi)容來自《Redis開發(fā)與運(yùn)維》一書第八章,如轉(zhuǎn)載請聲明。 Redis所有的數(shù)據(jù)都...
    meng_philip123閱讀 18,901評論 2 29
  • Redis 是一個(gè)鍵值對數(shù)據(jù)庫(key-value DB)小作,數(shù)據(jù)庫的值可以是字符串亭姥、集合、列表等多種類型的對象顾稀,而...
    吳昂_ff2d閱讀 3,239評論 0 5
  • 對象 redis沒有直接使用SDS达罗、鏈表、字典静秆、壓縮列表粮揉、整數(shù)集合等數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn) 鍵值對數(shù)據(jù)庫,而是基于這些數(shù)...
    稻殼_be03閱讀 511評論 0 0
  • 使用對象的好處:在執(zhí)行命令之前抚笔,根據(jù)對象的類型來判斷一個(gè)對象是否可以執(zhí)行給定的命令扶认。2.可以針對不同的使用場景,為...
    黑金星閱讀 251評論 0 1