給企業(yè)做網(wǎng)站的業(yè)務員免費注冊個人網(wǎng)站
集群
槽指派
CLUSTER ADDSLOTS命令的實現(xiàn)
CLUSTER ADDSLOTS命令接受一個或多個槽作為參數(shù),并將所有輸入的槽指派給接收該命令的節(jié)點負責:
CLUSTER ADDSLOTS <slot> [slot ...]
CLUSTER ADDSLOTS命令的實現(xiàn)可以用以下偽代碼來表示:
def CLUSTER_ADDSLOTS(*all_input_slots):# 遍歷所有輸入槽,檢查它們是否都是未指派槽for i in all_input_slots:# 如果有哪怕一個槽已經(jīng)被指派給了某個節(jié)點# 那么向客戶端返回錯誤,并終止命令執(zhí)行if clusterState.slots[i] != null:reply_error()return# 如果所有輸入槽都是未指派槽# 那么再次遍歷所有輸入槽,將這些槽指派給當前節(jié)點for i in all_input_slots:# 設置clusterState結構的slots數(shù)組# 將slots[i]的指針指向代表當前節(jié)點的clusterNode結構clusterState.slots[i] = clusterState.myself# 訪問代表當前節(jié)點的clusterNode結構的slots數(shù)組# 將數(shù)組在索引i上的二進制位設置為1setSlotBit(clusterState.myself.slots, i);
例子
- 舉個例子。如圖展示了一個節(jié)點的clusterState結構,clusterState.slots數(shù)組中的所有指針都指向NULL,并且clusterNode.slots數(shù)組中的所有二進制位的值都是0,這說明當前節(jié)點沒有被指派任何槽,并且集群
中的所有槽都是未指派的。當客戶端對如圖所示的節(jié)點執(zhí)行命令:
CLUSTER ADDSLOTS 1 2
將槽1和槽2指派給節(jié)點之后,節(jié)點的clusterState結構將被更新為如圖所示的樣子:
1.clusterState.slots數(shù)組在索引1和索引2上的指針指向了代表當前節(jié)點的clusterNode
2.并且clusterNode.slots數(shù)組在索引1和索引2上的為止被設置成了1
最后,在CLUSTER ADDSLOTS命令執(zhí)行完畢之后,節(jié)點會通過發(fā)送消息告知集群中的其他節(jié)點,自己目前正在處理哪些槽
在集群中執(zhí)行命令
在對數(shù)據(jù)庫中的16384個槽都進行了指派之后,集群就會進入上線狀態(tài),這時客戶端就可以向集群中的節(jié)點發(fā)送數(shù)據(jù)命令了,當客戶端向節(jié)點發(fā)送與數(shù)據(jù)庫鍵有關的命令時,接收命令的節(jié)點會計算出命令要處理的數(shù)據(jù)庫鍵屬于哪個槽,并檢查這個槽是否指派給了自己:
- 1.如果鍵所在的槽正好就指派給了當前節(jié)點,那么節(jié)點直接執(zhí)行這個命令
- 2.如果鍵所在的槽并沒有指派給當前節(jié)點,那么節(jié)點會向客戶端返回一個MOVED錯誤,指引客戶端轉(zhuǎn)向(redirect)至正確的節(jié)點,并再次發(fā)送之前想要執(zhí)行的命令,如圖所示
例子
- 舉個例子。如果在之前提到的由7000、7001、7002三個節(jié)點組成的集群中,用客戶端連上節(jié)點7000,并發(fā)送以下命令,那么命令會直接被節(jié)點7000執(zhí)行:
127.0.0.1:7000> SET date "2024-04-10"
OK
因為鍵date所在的槽2022正式由節(jié)點7000負責處理的。但是,如果執(zhí)行以下命令,那么客戶端會先被轉(zhuǎn)向至節(jié)點7001,然后再執(zhí)行命令
127.0.0.1:7000> SET msg "happy new year!"
-> Redirected to slot[6257] located at 127.0.0.1:7001
OK127.0.0.1:7001> GET msg
"happy new year!"
這是因為msg所在的槽6257是由節(jié)點7001負責處理的,而不是由最初接收命令的節(jié)點7000負責處理:
1.當客戶端第一次向節(jié)點7000發(fā)送SET命令的時候,節(jié)點7000會向客戶端返回MOVED錯誤,指引客戶端轉(zhuǎn)向至節(jié)點7001
2.當客戶端轉(zhuǎn)向到節(jié)點7001之后,客戶端重新向節(jié)點7001發(fā)送SET命令,這個命令會被節(jié)點7001成功執(zhí)行
計算鍵屬于哪個鍵
節(jié)點使用以下算法來計算給定鍵key屬于哪個槽:
def slot_number(key):return CRC16(key) & 16383
其中CRC16(key)語句用于計算鍵key的CRC-16校驗和,而& 16383語句則用于計算出一個介于0~16383之間的整數(shù)作為鍵key的槽號??梢允褂肅LUSTER KEYSLOT 命令可以查看一個給定鍵屬于哪個槽:
127.0.0.1:7000> CLUSTER KEYSLOT "date"
(integer) 2022
127.0.0.1:7000> CLUSTER KEYSLOT "msg"
(integer) 6257
127.0.0.1:7000> CLUSTER KEYSLOT "name"
(integer) 5798
127.0.0.1:7000> CLUSTER KEYSLOT "fruits"
(integer) 14943
CLUSTER KEYSLOT命令就是通過調(diào)用上面給出的槽分配算法來實現(xiàn)的,以下是該命令的偽代碼實現(xiàn):
def CLUSTER_KEYSLOT(key):
# 計算槽號
slot = slot_number(key)# 將槽號返回給客戶端
reply_client(slot)
判斷槽是否由當前節(jié)點負責處理。
當節(jié)點計算出鍵所屬的槽i之后,節(jié)點就會檢查自己在clusterState.slots數(shù)組中的項i,判斷鍵所在的槽是否由自己負責:
- 1.如果clusterState.slots[i]等于clusterState.myself,那么說明槽i由當前節(jié)點負責,節(jié)點可以執(zhí)行客戶端發(fā)送的命令
- 2.如果clusterState.slots[i]不等于clusterState.myself,那么說明槽i并非由當前節(jié)點負責,節(jié)點會根據(jù)clusterState.slots[i]指向的clusterNode結構所記錄的節(jié)點IP和端口號,向客戶端返回MOVED錯誤,指引客戶端轉(zhuǎn)向至正在處理槽i的節(jié)點
例子
- 舉個例子。假設如圖所示為節(jié)點7000的clusterState結構:
1.當客戶端向節(jié)點7000發(fā)送命令SET date "2024-04-10"的時候,節(jié)點首先計算出鍵date屬于槽2022,然后檢查得出clusterState.slots[2022]等于clusterState.myself,這說明槽2022正是由節(jié)點7000負責,
于是節(jié)點7000直接執(zhí)行這個SET命令,并將結果返回發(fā)送命令的客戶端
2.當客戶端向節(jié)點7000發(fā)送命令SET msg "happy new year!"的時候,節(jié)點首先計算出鍵msg屬于槽6257,然后檢查clusterState.slots[6257]是否等于clusterState.myself,結果發(fā)現(xiàn)兩者并不相等:這說明槽6257并非
由節(jié)點7000負責處理,于是節(jié)點7000訪問clusterState.slots[6257]所指向的clusterNode結構,并根據(jù)結構中記錄的IP地址127.0.0.1和端口號7001,向客戶端返回錯誤MOVED 6257 127.0.0.1:7001,指引節(jié)點轉(zhuǎn)向至正在負責處理槽6257的節(jié)點7001