內(nèi)容部分摘自于《Redis的設(shè)計(jì)與實(shí)現(xiàn)》(17章節(jié))
Redis 集群的重新分片操作是由 Redis 的集群管理軟件 redis-trib 負(fù)責(zé)執(zhí)行的闯两, Redis 提供了進(jìn)行重新分片所需的所有命令畸颅,而 redis-trib 則通過向源節(jié)點(diǎn)和目標(biāo)節(jié)點(diǎn)發(fā)送命令來進(jìn)行重新分片操作。
redis-trib 對(duì)集群的單個(gè)槽slot進(jìn)行重新分片的步驟如下:
- redis-trib對(duì)目標(biāo)節(jié)點(diǎn)發(fā)送 CLUSTER SETSLOT <slot> IMPORTING <source_id>命令弄捕,讓目標(biāo)節(jié)點(diǎn)準(zhǔn)備好從源節(jié)點(diǎn)導(dǎo)入(import)屬于槽slot的鍵值對(duì)巫延。
- redis-trib對(duì)源節(jié)點(diǎn)發(fā)送CLUSTER SETSLOT <slot> MIGRATING <target_id> 命令,源節(jié)點(diǎn)準(zhǔn)備好將屬于槽slot 的鍵值對(duì)遷移(migrate)至目標(biāo)節(jié)點(diǎn)。
- redis-trib向源節(jié)點(diǎn)發(fā)送CLUSTER GETKEYSINSLOT <slot> <count>命令珠叔,獲得最多count個(gè)屬于槽slot的鍵值對(duì)的鍵名(key name)。
- 對(duì)于步驟3獲得的每個(gè)鍵名弟劲,redis-trib都向源節(jié)點(diǎn)發(fā)送一個(gè)MIGRATE <target_ip> <target_port> <key_name> 0 <timeout>命令祷安,將被選中的鍵原子地從源節(jié)點(diǎn)遷移到目標(biāo)節(jié)點(diǎn)。
- 重復(fù)執(zhí)行步驟3和步驟4兔乞,直到源節(jié)點(diǎn)保存的所有屬于槽slot的鍵值對(duì)都被遷移到目標(biāo)節(jié)點(diǎn)為止汇鞭,每次遷移鍵的過程如下圖所示
- redis-trib 向集群中的任意一個(gè)節(jié)點(diǎn)發(fā)送CLUSTER SETSLOT <slot> NODE <target_id>命令,將槽 slot指派給目標(biāo)節(jié)點(diǎn)庸追,這一指派信息會(huì)通過消息發(fā)送至整個(gè)集群霍骄,最終集群中的所有節(jié)點(diǎn)都會(huì)知道槽slot已經(jīng)指派給了目標(biāo)節(jié)點(diǎn)
如果重新分片涉及多個(gè)槽,那么redis-trib將對(duì)每個(gè)給定的槽分別執(zhí)行上面給出的步驟淡溯。
假設(shè)我們有三臺(tái)redis集群(不考慮從機(jī)器)读整,node0(127.0.0.1:7000)、node1(127.0.0.1:7001)咱娶、node2(127.0.0.1:7002)米间,現(xiàn)在我們需要新加一臺(tái)node3(127.0.0.1:7003)機(jī)器,這時(shí)候會(huì)發(fā)現(xiàn)重新分片膘侮。
假設(shè)槽8000(存在多個(gè)key屈糊,key0、key1琼了、key2)逻锐、8001需要從node2遷移到node3上,對(duì)應(yīng)上面過程中表伦,node2 就為源節(jié)點(diǎn)谦去, node3 為目標(biāo)節(jié)點(diǎn)。
如果在這個(gè)重新分片的過程蹦哼,剛好請(qǐng)求的key在發(fā)生轉(zhuǎn)移的過程鳄哭,因?yàn)樵垂?jié)點(diǎn)記錄了要遷移的目標(biāo)節(jié)點(diǎn),即使請(qǐng)求到源節(jié)點(diǎn)上纲熏,這個(gè)key并不存在與源節(jié)點(diǎn)妆丘,此時(shí)會(huì)返回一個(gè)ASK錯(cuò)誤锄俄,并將請(qǐng)求轉(zhuǎn)發(fā)給key存在目標(biāo)節(jié)點(diǎn)。