在對(duì)數(shù)據(jù)庫中的16384個(gè)槽都進(jìn)行了指派之后,集群就會(huì)進(jìn)入上線狀態(tài),這時(shí)客戶端就可以向集群中的節(jié)點(diǎn)發(fā)送數(shù)據(jù)命令了。
當(dāng)客戶端向節(jié)點(diǎn)發(fā)送與數(shù)據(jù)庫鍵有關(guān)的命令時(shí),接收命令的節(jié)點(diǎn)會(huì)計(jì)算出命令要處理的數(shù)據(jù)庫鍵屬于哪個(gè)槽,并檢查這個(gè)槽是否指派給了自己:
- 如果鍵所在的槽正好就指派給了當(dāng)前節(jié)點(diǎn),那么節(jié)點(diǎn)直接執(zhí)行這個(gè)命令
- 如果將所在的槽并沒有指派給當(dāng)前節(jié)點(diǎn),那么節(jié)點(diǎn)會(huì)向客戶端返回一個(gè)MOVED錯(cuò)誤,指引客戶端轉(zhuǎn)向(redirect)至正確的節(jié)點(diǎn),并在此發(fā)送之前想要執(zhí)行的命令。
本節(jié)接下來的內(nèi)容將介紹計(jì)算鍵所屬槽的方法,節(jié)點(diǎn)判斷某個(gè)槽是否由自己負(fù)責(zé)的方法,以及MOVED錯(cuò)誤的實(shí)現(xiàn)方法,最后,本節(jié)還會(huì)介紹節(jié)點(diǎn)和單機(jī)Redis服務(wù)器保存鍵值對(duì)的相同和不同之處。
3.1 計(jì)算鍵屬于哪個(gè)槽
節(jié)點(diǎn)使用以下算法來計(jì)算給定鍵key屬于哪個(gè)槽:
def slot_number(key):
return CRC16(key) & 16383
其中CRC16(key)語句用于計(jì)算鍵key的CRC-16校驗(yàn)和,而&16383語句則用于計(jì)算出一個(gè)介于0至16383之間的整數(shù)作為鍵key的槽號(hào)。
使用CLUSTER KEYSLOT <key>命令可以查看一個(gè)給定鍵屬于哪個(gè)槽,以下是該命令的偽代碼實(shí)現(xiàn):
def CLUSTER_KEYSLOT(key):
# 計(jì)算槽號(hào)
slot = slot_number(key)
# 將槽號(hào)返回給客戶端
reply_client(slot)
3.2 判斷槽是否由當(dāng)前節(jié)點(diǎn)負(fù)責(zé)處理
當(dāng)節(jié)點(diǎn)計(jì)算出鍵所屬的槽i之后,節(jié)點(diǎn)就會(huì)檢查自己在clusterState.slots數(shù)組中的項(xiàng)i,判斷鍵所在的槽是否由自己負(fù)責(zé):
- 如果clusterState.slots[i]等于clusterState.myself,那么說明槽i由當(dāng)前節(jié)點(diǎn)負(fù)責(zé),節(jié)點(diǎn)可以執(zhí)行客戶端發(fā)送的命令。
- 如果clusterState.slots[i]不等于clusterState.myself,那么說明槽i并非由當(dāng)前節(jié)點(diǎn)負(fù)責(zé),節(jié)點(diǎn)會(huì)根據(jù)clusterState.slots[i]指向的clusterNode結(jié)構(gòu)所記錄的節(jié)點(diǎn)IP和端口號(hào),向客戶端返回MOVED錯(cuò)誤,指引客戶端轉(zhuǎn)向至正在處理槽i的節(jié)點(diǎn)。
3.3 MOVED錯(cuò)誤
當(dāng)節(jié)點(diǎn)發(fā)現(xiàn)鍵所在的槽并非由自己負(fù)責(zé)處理的時(shí)候,節(jié)點(diǎn)就會(huì)向客戶端返回一個(gè)MOVED錯(cuò)誤,指引客戶端轉(zhuǎn)向至正在負(fù)責(zé)槽的節(jié)點(diǎn)。
MOVED錯(cuò)誤的格式為:
MOVED <slot> <ip>:<port>
其中slot為鍵所在的槽,而ip和port則是負(fù)責(zé)處理槽slot的節(jié)點(diǎn)的IP地址和端口號(hào)
當(dāng)客戶端接收到節(jié)點(diǎn)返回的MOVED錯(cuò)誤時(shí),客戶端會(huì)根據(jù)MOVED錯(cuò)誤中提供的IP地址和端口號(hào),轉(zhuǎn)向至負(fù)責(zé)處理槽slot的節(jié)點(diǎn),并向該節(jié)點(diǎn)重新發(fā)送之前想要執(zhí)行的命令。
一個(gè)集群客戶端通常會(huì)與集群中的多個(gè)節(jié)點(diǎn)創(chuàng)建套接字連接,而所謂的節(jié)點(diǎn)轉(zhuǎn)向?qū)嶋H上就是換一個(gè)套接字來發(fā)送命令。
如果客戶端尚未與想要轉(zhuǎn)向的節(jié)點(diǎn)創(chuàng)建套接字連接,那么客戶端會(huì)現(xiàn)根據(jù)MOVED錯(cuò)誤提供的IP地址和端口號(hào)來連接節(jié)點(diǎn),然后再進(jìn)行轉(zhuǎn)向。
3.4 節(jié)點(diǎn)數(shù)據(jù)庫的實(shí)現(xiàn)
節(jié)點(diǎn)和單機(jī)服務(wù)器在數(shù)據(jù)庫方面的一個(gè)區(qū)別是,節(jié)點(diǎn)只能使用0號(hào)數(shù)據(jù)庫,而單機(jī)Redis服務(wù)器則沒有這一限制。