redis集群 第二節(jié) 槽指派

Redis集群通過分片的方式來保存數(shù)據(jù)庫中的鍵值對(duì):集群的整個(gè)數(shù)據(jù)庫被分為16384個(gè)槽(slot),數(shù)據(jù)庫中每個(gè)鍵都屬于這16384個(gè)槽的其中一個(gè)瓤漏,集群中的每個(gè)節(jié)點(diǎn)可以處理0個(gè)或最多16384個(gè)槽凿将。
當(dāng)數(shù)據(jù)庫總的16384個(gè)槽都有節(jié)點(diǎn)在處理時(shí)校套,集群處于上線狀態(tài)(ok);相反地牧抵,如果數(shù)據(jù)庫中有任何一個(gè)槽沒有得到處理前普,那么集群處于下線狀態(tài)(fail)拴测。
通過向節(jié)點(diǎn)發(fā)送CLUSTER ADDSLOTS命令,我們可以將一個(gè)或多個(gè)槽指派(assign)給節(jié)點(diǎn)負(fù)責(zé):

CLUSTER ADDSLOTS <slot> [slot ...]

本節(jié)接下來的內(nèi)容將首先介紹節(jié)點(diǎn)保存槽指派信息的方法,以及節(jié)點(diǎn)之間傳播槽指派信息的方法浦夷,之后再介紹CLUSTER ADDSLOTS命令的實(shí)現(xiàn)。

2.1 記錄節(jié)點(diǎn)的槽指派信息

clusterNode結(jié)構(gòu)的slots屬性和numslot屬性記錄了節(jié)點(diǎn)負(fù)責(zé)處理哪些槽:

struct clusterNode {
// ...
unsigned char slots[16384/8];
int numslots;
// ...
};

slots屬性是一個(gè)二進(jìn)制位數(shù)組(bit array)举娩,這個(gè)數(shù)組的長(zhǎng)度為16384/8=2048個(gè)字節(jié)馒稍,共包含16384個(gè)二進(jìn)制位。
Redis以0為起始索引映琳,16383為終止索引机隙,對(duì)slots數(shù)組中的16384個(gè)二進(jìn)制位進(jìn)行編號(hào),并根據(jù)索引i上的二進(jìn)制位的值來判斷節(jié)點(diǎn)是否負(fù)責(zé)處理槽i:

  • 如果slots數(shù)組在索引i上的二進(jìn)制位的值為1萨西,那么表示節(jié)點(diǎn)負(fù)責(zé)處理槽i有鹿;
  • 如果slots數(shù)組在索引i上的二進(jìn)制位的值為0,那么表示節(jié)點(diǎn)不負(fù)責(zé)處理槽i谎脯;

至于numslots屬性則記錄節(jié)點(diǎn)負(fù)責(zé)處理的槽的數(shù)量葱跋,也即是slots數(shù)組中值為1的二進(jìn)制位的數(shù)量。

2.2 傳播節(jié)點(diǎn)的槽指派信息

一個(gè)節(jié)點(diǎn)除了會(huì)將自己負(fù)責(zé)處理的槽記錄在clusterNode結(jié)構(gòu)的slots屬性和numslots屬性之外源梭,它還會(huì)將自己的slots數(shù)組通過消息發(fā)送給集群中的其他節(jié)點(diǎn)娱俺,以此來告知其他節(jié)點(diǎn)自己目前負(fù)責(zé)處理哪些槽。
當(dāng)節(jié)點(diǎn)A通過消息從節(jié)點(diǎn)B那里接收到節(jié)點(diǎn)B的slots數(shù)組時(shí)废麻,節(jié)點(diǎn)A會(huì)在自己的clusterState.nodes字典中查找節(jié)點(diǎn)B對(duì)應(yīng)的clusterNode結(jié)構(gòu)荠卷,并對(duì)結(jié)構(gòu)中的slots數(shù)組進(jìn)行保存或者更新。
因?yàn)榧褐械拿總€(gè)節(jié)點(diǎn)都會(huì)將自己的slots數(shù)組通過消息發(fā)送給集群中的其他節(jié)點(diǎn)烛愧,并且每個(gè)接收到slots數(shù)組的節(jié)點(diǎn)都會(huì)將數(shù)組保存到相應(yīng)節(jié)點(diǎn)的clusterNode結(jié)構(gòu)里面油宜,因此掂碱,集群中的每個(gè)節(jié)點(diǎn)都會(huì)知道數(shù)據(jù)庫中的16384個(gè)槽分別被指派給了集群中的哪些節(jié)點(diǎn)。

2.3 記錄集群所有槽的指派信息

clusterState結(jié)構(gòu)中的slots數(shù)組記錄了集群中所有16384個(gè)槽的指派信息:
typedef struct clusterState {
// ...
clusterNode *slots[16384];
// ...
} clusterState;
slots數(shù)組包含了16384個(gè)項(xiàng)慎冤,每個(gè)數(shù)組項(xiàng)都是一個(gè)指向clusterNode結(jié)構(gòu)的指針:

  • 如果slots[i]指針指向NULL疼燥,那么表示槽i尚未指派給任何節(jié)點(diǎn)。
  • 如果slots[i]指針指向一個(gè)clusterNode結(jié)構(gòu)蚁堤,那么表示槽i已經(jīng)指派給了clusterNode結(jié)構(gòu)所代表的節(jié)點(diǎn)醉者。

如果只將槽指派信息保存在各個(gè)節(jié)點(diǎn)的clusterNode.slots數(shù)組里,會(huì)出現(xiàn)一些無法高效地解決的問題违寿,而clusterState.slots數(shù)組的存在解決了這些問題:

  • 如果節(jié)點(diǎn)只使用clusterNode.slots數(shù)組來記錄槽的指派信息湃交,那么為了知道槽i是否已經(jīng)被指派,或者槽i被指派給了哪個(gè)節(jié)點(diǎn)藤巢,程序需要遍歷clusterState.nodes字典中的所有clusterNode結(jié)構(gòu)搞莺,檢查這些結(jié)構(gòu)的slots數(shù)組,直到找到負(fù)責(zé)處理槽i的節(jié)點(diǎn)為止掂咒,這個(gè)過程的復(fù)雜度為O(N)才沧,其中N為clusterState.nodes字典保存的clusterNode結(jié)構(gòu)的數(shù)量。
  • 而通過將所有槽的指派信息保存在clusterState.slots數(shù)組里面绍刮,程序要檢查槽i是否已經(jīng)被指派温圆,又或者取得負(fù)責(zé)處理槽i的節(jié)點(diǎn),只需要訪問clusterState.slots[i]的值即可孩革,這個(gè)操作的復(fù)雜度僅為O(1)岁歉。

要說明的一點(diǎn)是,雖然clusterState.slots數(shù)組中記錄了集群中所有槽的指派信息膝蜈,但使用clusterNode結(jié)構(gòu)的slots數(shù)組來記錄單個(gè)節(jié)點(diǎn)的槽指派信息仍然是有必要的:

  • 因?yàn)楫?dāng)程序需要將某個(gè)節(jié)點(diǎn)的槽指派信息通過消息發(fā)送給其他節(jié)點(diǎn)時(shí)锅移,程序只需要將相應(yīng)節(jié)點(diǎn)的clusterNode.slots數(shù)組整個(gè)發(fā)送出去就可以了。
  • 另一方面饱搏,如果Redis不使用clusterNode.slots數(shù)組非剃,而單獨(dú)使用clusterState.slots數(shù)組的話,那么每次要將節(jié)點(diǎn)A的槽指派信息傳播給其他節(jié)點(diǎn)時(shí)推沸,程序必須先遍歷整個(gè)clusterState.slots數(shù)組备绽,記錄節(jié)點(diǎn)A負(fù)責(zé)處理哪些槽,然后才能發(fā)送節(jié)點(diǎn)A的槽指派信息鬓催,這比直接發(fā)送clusterNode.slots數(shù)組要麻煩和低效得多肺素。
    clusterState.slots數(shù)組記錄了集群中所有槽的指派信息,而clusterNode.slots數(shù)組只記錄了clusterNode結(jié)構(gòu)所代表的節(jié)點(diǎn)的槽指派信息深浮,這是兩個(gè)slots數(shù)組的關(guān)鍵區(qū)別所在压怠。

2.4 CLUSTER ADDSLOTS命令的實(shí)現(xiàn)

CLUSTER ADDSLOTS命令接受一個(gè)或多個(gè)槽作為參數(shù),并將所有輸入的槽指派給接收該命令的節(jié)點(diǎn)負(fù)責(zé):

CLUSTER ADDSLOTS <slot> [slot ...]

CLUSTER ADDSLOTS命令的實(shí)現(xiàn)可以用以下偽代碼來表示:

def CLUSTER_ADDSLOTS(*all_input_slots):
# 遍歷所有輸入槽飞苇,檢查它們是否都是未指派槽
for i in all_input_slots:
# 如果有哪怕一個(gè)槽已經(jīng)被指派給了某個(gè)節(jié)點(diǎn)
# 那么向客戶端返回錯(cuò)誤菌瘫,并終止命令執(zhí)行
if clusterState.slots[i] != NULL:
reply_error()
return
# 如果所有輸入槽都是未指派槽
# 那么再次遍歷所有輸入槽,將這些槽指派給當(dāng)前節(jié)點(diǎn)
for i in all_input_slots:
# 設(shè)置clusterState結(jié)構(gòu)的slots數(shù)組
# 將slots[i]的指針指向代表當(dāng)前節(jié)點(diǎn)的clusterNode結(jié)構(gòu)
clusterState.slots[i] = clusterState.myself
# 訪問代表當(dāng)前節(jié)點(diǎn)的clusterNode結(jié)構(gòu)的slots數(shù)組
# 將數(shù)組在索引i上的二進(jìn)制位設(shè)置為1
setSlotBit(clusterState.myself.slots, i)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末布卡,一起剝皮案震驚了整個(gè)濱河市雨让,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌忿等,老刑警劉巖栖忠,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異贸街,居然都是意外死亡庵寞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門薛匪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捐川,“玉大人,你說我怎么就攤上這事逸尖」帕ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵娇跟,是天一觀的道長(zhǎng)岩齿。 經(jīng)常有香客問我,道長(zhǎng)苞俘,這世上最難降的妖魔是什么盹沈? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮吃谣,結(jié)果婚禮上乞封,老公的妹妹穿的比我還像新娘。我一直安慰自己基协,他們只是感情好歌亲,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著澜驮,像睡著了一般陷揪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杂穷,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天悍缠,我揣著相機(jī)與錄音,去河邊找鬼耐量。 笑死飞蚓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的廊蜒。 我是一名探鬼主播趴拧,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼溅漾,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了著榴?” 一聲冷哼從身側(cè)響起添履,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脑又,沒想到半個(gè)月后暮胧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡问麸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年往衷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片严卖。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡席舍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妄田,到底是詐尸還是另有隱情俺亮,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布疟呐,位于F島的核電站脚曾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏启具。R本人自食惡果不足惜本讥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鲁冯。 院中可真熱鬧拷沸,春花似錦、人聲如沸薯演。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跨扮。三九已至序无,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間衡创,已是汗流浹背帝嗡。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留璃氢,地道東北人哟玷。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像一也,于是被迫代替她去往敵國和親巢寡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喉脖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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