Mac多端口搭建redis集群

集群(Redis Cluster)作用:

1.數(shù)據(jù)分區(qū):

數(shù)據(jù)分區(qū)(或稱數(shù)據(jù)分片)是集群最核心的功能篷帅,集群將數(shù)據(jù)分散到多個(gè)節(jié)點(diǎn)琐脏。

一方面突破了 Redis 單機(jī)內(nèi)存大小的限制榨咐,存儲(chǔ)容量大大增加伦仍。

另一方面每個(gè)主節(jié)點(diǎn)都可以對(duì)外提供讀服務(wù)和寫服務(wù),大大提高了集群的響應(yīng)能力磕蒲。

Redis 單機(jī)內(nèi)存大小受限問(wèn)題加缘,在介紹持久化和主從復(fù)制時(shí)都有提及沿侈。

例如斗忌,如果單機(jī)內(nèi)存太大质礼,bgsave 和 bgrewriteaof 的 fork 操作可能導(dǎo)致主進(jìn)程阻塞,主從環(huán)境下主機(jī)切換時(shí)可能導(dǎo)致從節(jié)點(diǎn)長(zhǎng)時(shí)間無(wú)法提供服務(wù)织阳,全量復(fù)制階段主節(jié)點(diǎn)的復(fù)制緩沖區(qū)可能溢出眶蕉。

2.高可用:

集群支持主從復(fù)制和主節(jié)點(diǎn)的自動(dòng)故障轉(zhuǎn)移(與哨兵類似),當(dāng)任一節(jié)點(diǎn)發(fā)生故障時(shí)唧躲,集群仍然可以對(duì)外提供服務(wù)造挽。

集群的搭建:

本案例以三主三從搭建簡(jiǎn)單的集群,主庫(kù)(6379惊窖、6378刽宪、6377)厘贼, 從庫(kù)(6380界酒、6381、6382),所有節(jié)點(diǎn)在同一臺(tái)服務(wù)器上嘴秸,以端口號(hào)進(jìn)行區(qū)分毁欣。

2.1安裝redis(6379)

brew? install? redis

設(shè)置為開機(jī)啟動(dòng)項(xiàng):ln -sfv /usr/local/opt/redis/*.plist ~/Library/LaunchAgents

使用launchctl啟動(dòng)redis.server:? launchctl load ~/Library/LaunchAgents/homebrew.mxcl.redis.plist

使用配置文件啟動(dòng)redis : redis-server /usr/local/etc/redis.conf

測(cè)試redis是否啟動(dòng):redis-cli ping

默認(rèn)啟動(dòng)就會(huì)運(yùn)行redis-server:

vim /usr/local/etc/redis.conf

修改: daemonize no? 為 daemonize yes

查看redis安裝信息:brew info redis

停止redis:? ? ? ./redis-cli? ? ?shutdown

2.2 創(chuàng)建兩個(gè)從redis實(shí)例: ??

拷貝主redis(6379)的配置文件redis.conf庇谆,命名為redis_6380.conf、redis_6381.conf

修改redis_6380.conf文件凭疮,將6379全部更換為6380(6381也一樣),如下圖:

啟動(dòng)6380饭耳,6381

2.3搭建集群:

啟動(dòng)節(jié)點(diǎn):

將節(jié)點(diǎn)以集群模式啟動(dòng),此時(shí)節(jié)點(diǎn)是獨(dú)立的执解,并沒(méi)有建立聯(lián)系

節(jié)點(diǎn)握手:

讓獨(dú)立的節(jié)點(diǎn)連成一個(gè)網(wǎng)絡(luò)

分配槽:

將 16384 個(gè)槽分配給主節(jié)點(diǎn)(6379寞肖、6378、6377)

指定主從關(guān)系:

為從節(jié)點(diǎn)指定主節(jié)點(diǎn)

啟動(dòng)節(jié)點(diǎn):集群節(jié)點(diǎn)的啟動(dòng)仍然是使用 redis-server 命令衰腌,但需要使用集群模式啟動(dòng)

redis(6379)的配置文件如下:

其中的 cluster-enabled 和 cluster-config-file 是與集群相關(guān)的配置新蟆。

cluster-enabledyes:Redis 實(shí)例可以分為單機(jī)模式(standalone)和集群模式(cluster);cluster-enabledyes 可以啟動(dòng)集群模式右蕊。

在單機(jī)模式下啟動(dòng)的 Redis 實(shí)例琼稻,如果執(zhí)行 info server 命令,可以發(fā)現(xiàn) redis_mode 一項(xiàng)為 standalone饶囚,如下圖所示:? ??

集群模式下的節(jié)點(diǎn)帕翻,其 redis_mode 為 cluster,如下圖所示

cluster-config-file:該參數(shù)指定了集群配置文件的位置萝风。每個(gè)節(jié)點(diǎn)在運(yùn)行過(guò)程中嘀掸,會(huì)維護(hù)一份集群配置文件。

每當(dāng)集群信息發(fā)生變化時(shí)(如增減節(jié)點(diǎn))闹丐,集群內(nèi)所有節(jié)點(diǎn)會(huì)將最新信息更新到該配置文件横殴。

當(dāng)節(jié)點(diǎn)重啟后,會(huì)重新讀取該配置文件卿拴,獲取集群信息衫仑,可以方便的重新加入到集群中。

也就是說(shuō)堕花,當(dāng) Redis 節(jié)點(diǎn)以集群模式啟動(dòng)時(shí)文狱,會(huì)首先尋找是否有集群配置文件。

如果有則使用文件中的配置啟動(dòng)缘挽;如果沒(méi)有瞄崇,則初始化配置并將配置保存到文件中。集群配置文件由 Redis 節(jié)點(diǎn)維護(hù)壕曼,不需要人工修改苏研。

編輯好配置文件后,使用 redis-server 命令啟動(dòng)該節(jié)點(diǎn):

節(jié)點(diǎn)啟動(dòng)以后腮郊,通過(guò) cluster nodes 命令可以查看節(jié)點(diǎn)的情況摹蘑,如下圖所示:

其中返回值第一項(xiàng)表示節(jié)點(diǎn) id,由 40 個(gè) 16 進(jìn)制字符串組成轧飞,節(jié)點(diǎn) id 與主從復(fù)制一文中提到的 runId 不同衅鹿。

Redis 每次啟動(dòng) runId 都會(huì)重新創(chuàng)建撒踪,但是節(jié)點(diǎn) id 只在集群初始化時(shí)創(chuàng)建一次,然后保存到集群配置文件中大渤,以后節(jié)點(diǎn)重新啟動(dòng)時(shí)會(huì)直接在集群配置文件中讀取制妄。

其他節(jié)點(diǎn)使用相同辦法啟動(dòng),不再贅述泵三。需要特別注意耕捞,在啟動(dòng)節(jié)點(diǎn)階段,節(jié)點(diǎn)是沒(méi)有主從關(guān)系的烫幕,因此從節(jié)點(diǎn)不需要加 slaveof 配置砸脊。

節(jié)點(diǎn)握手:

節(jié)點(diǎn)啟動(dòng)以后是相互獨(dú)立的,并不知道其他節(jié)點(diǎn)存在纬霞;需要進(jìn)行節(jié)點(diǎn)握手凌埂,將獨(dú)立的節(jié)點(diǎn)組成一個(gè)網(wǎng)絡(luò)。

節(jié)點(diǎn)握手使用 cluster meet {ip} {port} 命令實(shí)現(xiàn)诗芜,例如在 6379 節(jié)點(diǎn)中執(zhí)行 clustermeet 172.20.28.75 6380瞳抓,可以完成 6379 節(jié)點(diǎn)和 6380 節(jié)點(diǎn)的握手。

注意:ip 使用的是局域網(wǎng) ip伏恐,而不是 localhost 或 127.0.0.1孩哑,是為了其他機(jī)器上的節(jié)點(diǎn)或客戶端也可以訪問(wèn)。為了操作簡(jiǎn)單翠桦,我這里還是使用的127.0.0.1横蜒。

在 6380 節(jié)點(diǎn)下也可以類似查看:

執(zhí)行完上述命令后,可以看到 6379 節(jié)點(diǎn)已經(jīng)感知到了所有其他節(jié)點(diǎn):

分配槽:

在 Redis 集群中销凑,借助槽實(shí)現(xiàn)數(shù)據(jù)分區(qū)丛晌。集群有 16384 個(gè)槽,槽是數(shù)據(jù)管理和遷移的基本單位斗幼。

當(dāng)數(shù)據(jù)庫(kù)中的 16384 個(gè)槽都分配了節(jié)點(diǎn)時(shí)澎蛛,集群處于上線狀態(tài)(ok);如果有任意一個(gè)槽沒(méi)有分配節(jié)點(diǎn)蜕窿,則集群處于下線狀態(tài)(fail)谋逻。

cluster info 命令可以查看集群狀態(tài),分配槽之前狀態(tài)為 fail:

分配槽使用 cluster addslots 命令桐经,執(zhí)行下面的命令將槽(編號(hào) 0-16383)全部分配完畢:

此時(shí)查看集群狀態(tài)毁兆,顯示所有槽分配完畢,集群進(jìn)入上線狀態(tài):

指定主從關(guān)系:

集群中指定主從關(guān)系不再使用 slaveof 命令阴挣,而是使用 cluster replicate 命令气堕;參數(shù)使用節(jié)點(diǎn) id。

通過(guò) cluster nodes 獲得幾個(gè)主節(jié)點(diǎn)的節(jié)點(diǎn) id 后,執(zhí)行下面的命令為每個(gè)從節(jié)點(diǎn)指定主節(jié)點(diǎn):

此時(shí)執(zhí)行 cluster nodes 查看各個(gè)節(jié)點(diǎn)的狀態(tài)送巡,可以看到主從關(guān)系已經(jīng)建立:

集群設(shè)計(jì)方案:

設(shè)計(jì)集群方案時(shí),至少要考慮以下因素:

高可用要求:根據(jù)故障轉(zhuǎn)移的原理盒卸,至少需要 3 個(gè)主節(jié)點(diǎn)才能完成故障轉(zhuǎn)移骗爆,且 3 個(gè)主節(jié)點(diǎn)不應(yīng)在同一臺(tái)物理機(jī)上。

每個(gè)主節(jié)點(diǎn)至少需要 1 個(gè)從節(jié)點(diǎn)蔽介,且主從節(jié)點(diǎn)不應(yīng)在一臺(tái)物理機(jī)上摘投;因此高可用集群至少包含 6 個(gè)節(jié)點(diǎn)。

數(shù)據(jù)量和訪問(wèn)量:估算應(yīng)用需要的數(shù)據(jù)量和總訪問(wèn)量(考慮業(yè)務(wù)發(fā)展虹蓄,留有冗余)犀呼,結(jié)合每個(gè)主節(jié)點(diǎn)的容量和能承受的訪問(wèn)量(可以通過(guò) benchmark 得到較準(zhǔn)確估計(jì)),計(jì)算需要的主節(jié)點(diǎn)數(shù)量薇组。

節(jié)點(diǎn)數(shù)量限制:Redis 官方給出的節(jié)點(diǎn)數(shù)量限制為 1000外臂,主要是考慮節(jié)點(diǎn)間通信帶來(lái)的消耗。

在實(shí)際應(yīng)用中應(yīng)盡量避免大集群律胀,如果節(jié)點(diǎn)數(shù)量不足以滿足應(yīng)用對(duì) Redis 數(shù)據(jù)量和訪問(wèn)量的要求宋光,可以考慮:①業(yè)務(wù)分割,大集群分為多個(gè)小集群炭菌;②減少不必要的數(shù)據(jù)罪佳;③調(diào)整數(shù)據(jù)過(guò)期策略等。

適度冗余:Redis 可以在不影響集群服務(wù)的情況下增加節(jié)點(diǎn)黑低,因此節(jié)點(diǎn)數(shù)量適當(dāng)冗余即可赘艳,不用太大

3.集群的基本原理

上面介紹了集群的搭建方法和設(shè)計(jì)方案,下面將進(jìn)一步深入克握,介紹集群的原理蕾管。

集群最核心的功能是數(shù)據(jù)分區(qū),因此:首先介紹數(shù)據(jù)的分區(qū)規(guī)則菩暗。然后介紹集群實(shí)現(xiàn)的細(xì)節(jié):通信機(jī)制和數(shù)據(jù)結(jié)構(gòu)娇掏。最后以 cluster meet(節(jié)點(diǎn)握手)、cluster addslots(槽分配)為例勋眯,說(shuō)明節(jié)點(diǎn)是如何利用上述數(shù)據(jù)結(jié)構(gòu)和通信機(jī)制實(shí)現(xiàn)集群命令的婴梧。

數(shù)據(jù)分區(qū)方案:

數(shù)據(jù)分區(qū)有順序分區(qū)、哈希分區(qū)等客蹋,其中哈希分區(qū)由于其天然的隨機(jī)性塞蹭,使用廣泛;集群的分區(qū)方案便是哈希分區(qū)的一種讶坯。

哈希分區(qū)的基本思路是:對(duì)數(shù)據(jù)的特征值(如 key)進(jìn)行哈希番电,然后根據(jù)哈希值決定數(shù)據(jù)落在哪個(gè)節(jié)點(diǎn)。

常見(jiàn)的哈希分區(qū)包括:哈希取余分區(qū)、一致性哈希分區(qū)漱办、帶虛擬節(jié)點(diǎn)的一致性哈希分區(qū)等这刷。

衡量數(shù)據(jù)分區(qū)方法好壞的標(biāo)準(zhǔn)有很多,其中比較重要的兩個(gè)因素是:

數(shù)據(jù)分布是否均勻娩井,增加或刪減節(jié)點(diǎn)對(duì)數(shù)據(jù)分布的影響暇屋。

由于哈希的隨機(jī)性,哈希分區(qū)基本可以保證數(shù)據(jù)分布均勻洞辣;因此在比較哈希分區(qū)方案時(shí)咐刨,重點(diǎn)要看增減節(jié)點(diǎn)對(duì)數(shù)據(jù)分布的影響。

哈希取余分區(qū)

哈希取余分區(qū)思路非常簡(jiǎn)單:計(jì)算 key 的 hash 值扬霜,然后對(duì)節(jié)點(diǎn)數(shù)量進(jìn)行取余定鸟,從而決定數(shù)據(jù)映射到哪個(gè)節(jié)點(diǎn)上。

該方案最大的問(wèn)題是著瓶,當(dāng)新增或刪減節(jié)點(diǎn)時(shí)联予,節(jié)點(diǎn)數(shù)量發(fā)生變化,系統(tǒng)中所有的數(shù)據(jù)都需要重新計(jì)算映射關(guān)系材原,引發(fā)大規(guī)模數(shù)據(jù)遷移躯泰。

一致性哈希分區(qū)

一致性哈希算法將整個(gè)哈希值空間組織成一個(gè)虛擬的圓環(huán),如下圖所示华糖,范圍為 0-2^32-1麦向。


對(duì)于每個(gè)數(shù)據(jù),根據(jù) key 計(jì)算 hash 值客叉,確定數(shù)據(jù)在環(huán)上的位置诵竭,然后從此位置沿環(huán)順時(shí)針行走,找到的第一臺(tái)服務(wù)器就是其應(yīng)該映射到的服務(wù)器兼搏。與哈希取余分區(qū)相比卵慰,一致性哈希分區(qū)將增減節(jié)點(diǎn)的影響限制在相鄰節(jié)點(diǎn)。

以上圖為例佛呻,如果在 node1 和 node2 之間增加 node5裳朋,則只有 node2 中的一部分?jǐn)?shù)據(jù)會(huì)遷移到 node5;如果去掉 node2吓著,則原 node2 中的數(shù)據(jù)只會(huì)遷移到 node4 中鲤嫡,只有 node4 會(huì)受影響。

一致性哈希分區(qū)的主要問(wèn)題在于绑莺,當(dāng)節(jié)點(diǎn)數(shù)量較少時(shí)暖眼,增加或刪減節(jié)點(diǎn),對(duì)單個(gè)節(jié)點(diǎn)的影響可能很大纺裁,造成數(shù)據(jù)的嚴(yán)重不平衡诫肠。

還是以上圖為例司澎,如果去掉 node2,node4 中的數(shù)據(jù)由總數(shù)據(jù)的 1/4 左右變?yōu)?1/2 左右栋豫,與其他節(jié)點(diǎn)相比負(fù)載過(guò)高挤安。

帶虛擬節(jié)點(diǎn)的一致性哈希分區(qū)

該方案在一致性哈希分區(qū)的基礎(chǔ)上,引入了虛擬節(jié)點(diǎn)的概念丧鸯。Redis 集群使用的便是該方案蛤铜,其中的虛擬節(jié)點(diǎn)稱為槽(slot)。

槽是介于數(shù)據(jù)和實(shí)際節(jié)點(diǎn)之間的虛擬概念骡送;每個(gè)實(shí)際節(jié)點(diǎn)包含一定數(shù)量的槽,每個(gè)槽包含哈希值在一定范圍內(nèi)的數(shù)據(jù)絮记。

引入槽以后摔踱,數(shù)據(jù)的映射關(guān)系由數(shù)據(jù) hash->實(shí)際節(jié)點(diǎn),變成了數(shù)據(jù) hash->槽->實(shí)際節(jié)點(diǎn)怨愤。

在使用了槽的一致性哈希分區(qū)中派敷,槽是數(shù)據(jù)管理和遷移的基本單位。槽解耦了數(shù)據(jù)和實(shí)際節(jié)點(diǎn)之間的關(guān)系撰洗,增加或刪除節(jié)點(diǎn)對(duì)系統(tǒng)的影響很小篮愉。

仍以上圖為例,系統(tǒng)中有 4 個(gè)實(shí)際節(jié)點(diǎn)差导,假設(shè)為其分配 16 個(gè)槽(0-15)试躏;槽 0-3 位于 node1,4-7 位于 node2设褐,以此類推颠蕴。

如果此時(shí)刪除 node2,只需要將槽 4-7 重新分配即可助析,例如槽 4-5 分配給 node1犀被,槽 6 分配給 node3,槽 7 分配給 node4外冀;可以看出刪除 node2 后寡键,數(shù)據(jù)在其他節(jié)點(diǎn)的分布仍然較為均衡。

槽的數(shù)量一般遠(yuǎn)小于 2^32雪隧,遠(yuǎn)大于實(shí)際節(jié)點(diǎn)的數(shù)量西轩;在 Redis 集群中,槽的數(shù)量為 16384脑沿。

上面這張圖很好的總結(jié)了 Redis 集群將數(shù)據(jù)映射到實(shí)際節(jié)點(diǎn)的過(guò)程:

Redis 對(duì)數(shù)據(jù)的特征值(一般是key)計(jì)算哈希值遭商,使用的算法是 CRC16。

根據(jù)哈希值捅伤,計(jì)算數(shù)據(jù)屬于哪個(gè)槽劫流。

根據(jù)槽與節(jié)點(diǎn)的映射關(guān)系,計(jì)算數(shù)據(jù)屬于哪個(gè)節(jié)點(diǎn)。

節(jié)點(diǎn)通信機(jī)制:

集群要作為一個(gè)整體工作祠汇,離不開節(jié)點(diǎn)之間的通信仍秤。

兩個(gè)端口

在哨兵系統(tǒng)中,節(jié)點(diǎn)分為數(shù)據(jù)節(jié)點(diǎn)和哨兵節(jié)點(diǎn):前者存儲(chǔ)數(shù)據(jù)可很,后者實(shí)現(xiàn)額外的控制功能诗力。

在集群中,沒(méi)有數(shù)據(jù)節(jié)點(diǎn)與非數(shù)據(jù)節(jié)點(diǎn)之分:所有的節(jié)點(diǎn)都存儲(chǔ)數(shù)據(jù)我抠,也都參與集群狀態(tài)的維護(hù)苇本。

為此,集群中的每個(gè)節(jié)點(diǎn)菜拓,都提供了兩個(gè) TCP 端口:

普通端口:即我們?cè)谇懊嬷付ǖ亩丝?6379 等)瓣窄。普通端口主要用于為客戶端提供服務(wù)(與單機(jī)節(jié)點(diǎn)類似);但在節(jié)點(diǎn)間數(shù)據(jù)遷移時(shí)也會(huì)使用纳鼎。

集群端口:端口號(hào)是普通端口+10000(10000 是固定值俺夕,無(wú)法改變),如 6379 節(jié)點(diǎn)的集群端口為 16379贱鄙。

集群端口只用于節(jié)點(diǎn)之間的通信劝贸,如搭建集群、增減節(jié)點(diǎn)逗宁、故障轉(zhuǎn)移等操作時(shí)節(jié)點(diǎn)間的通信映九;不要使用客戶端連接集群接口。為了保證集群可以正常工作瞎颗,在配置防火墻時(shí)氯迂,要同時(shí)開啟普通端口和集群端口。

Gossip協(xié)議:

節(jié)點(diǎn)間通信言缤,按照通信協(xié)議可以分為幾種類型:?jiǎn)螌?duì)單嚼蚀、廣播、Gossip 協(xié)議等管挟。重點(diǎn)是廣播和 Gossip 的對(duì)比轿曙。

廣播是指向集群內(nèi)所有節(jié)點(diǎn)發(fā)送消息;優(yōu)點(diǎn)是集群的收斂速度快(集群收斂是指集群內(nèi)所有節(jié)點(diǎn)獲得的集群信息是一致的)僻孝,缺點(diǎn)是每條消息都要發(fā)送給所有節(jié)點(diǎn)导帝,CPU、帶寬等消耗較大穿铆。

Gossip 協(xié)議的特點(diǎn)是:在節(jié)點(diǎn)數(shù)量有限的網(wǎng)絡(luò)中您单,每個(gè)節(jié)點(diǎn)都“隨機(jī)”的與部分節(jié)點(diǎn)通信(并不是真正的隨機(jī),而是根據(jù)特定的規(guī)則選擇通信的節(jié)點(diǎn))荞雏,經(jīng)過(guò)一番雜亂無(wú)章的通信虐秦,每個(gè)節(jié)點(diǎn)的狀態(tài)很快會(huì)達(dá)到一致平酿。

Gossip 協(xié)議的優(yōu)點(diǎn)有負(fù)載(比廣播)低、去中心化悦陋、容錯(cuò)性高(因?yàn)橥ㄐ庞腥哂?等蜈彼;缺點(diǎn)主要是集群的收斂速度慢。

消息類型:

集群中的節(jié)點(diǎn)采用固定頻率(每秒 10 次)的定時(shí)任務(wù)進(jìn)行通信相關(guān)的工作:判斷是否需要發(fā)送消息及消息類型俺驶、確定接收節(jié)點(diǎn)幸逆、發(fā)送消息等。

如果集群狀態(tài)發(fā)生了變化暮现,如增減節(jié)點(diǎn)还绘、槽狀態(tài)變更,通過(guò)節(jié)點(diǎn)間的通信栖袋,所有節(jié)點(diǎn)會(huì)很快得知整個(gè)集群的狀態(tài)拍顷,使集群收斂。

節(jié)點(diǎn)間發(fā)送的消息主要分為 5 種:

MEET 消息

PING 消息

PONG 消息

FAIL 消息

PUBLISH 消息

不同的消息類型栋荸,通信協(xié)議菇怀、發(fā)送的頻率和時(shí)機(jī)凭舶、接收節(jié)點(diǎn)的選擇等是不同的:

MEET 消息:在節(jié)點(diǎn)握手階段晌块,當(dāng)節(jié)點(diǎn)收到客戶端的 cluster meet 命令時(shí),會(huì)向新加入的節(jié)點(diǎn)發(fā)送 MEET 消息帅霜,請(qǐng)求新節(jié)點(diǎn)加入到當(dāng)前集群匆背;新節(jié)點(diǎn)收到 MEET 消息后會(huì)回復(fù)一個(gè) PONG 消息。

PING 消息:集群里每個(gè)節(jié)點(diǎn)每秒鐘會(huì)選擇部分節(jié)點(diǎn)發(fā)送 PING 消息身冀,接收者收到消息后會(huì)回復(fù)一個(gè) PONG 消息钝尸。PING 消息的內(nèi)容是自身節(jié)點(diǎn)和部分其他節(jié)點(diǎn)的狀態(tài)信息;作用是彼此交換信息搂根,以及檢測(cè)節(jié)點(diǎn)是否在線珍促。

PING 消息使用 Gossip 協(xié)議發(fā)送,接收節(jié)點(diǎn)的選擇兼顧了收斂速度和帶寬成本剩愧,具體規(guī)則如下:①隨機(jī)找 5 個(gè)節(jié)點(diǎn)猪叙,在其中選擇最久沒(méi)有通信的 1 個(gè)節(jié)點(diǎn)。②掃描節(jié)點(diǎn)列表仁卷,選擇最近一次收到 PONG 消息時(shí)間大于 cluster_node_timeout/2 的所有節(jié)點(diǎn)穴翩,防止這些節(jié)點(diǎn)長(zhǎng)時(shí)間未更新。

PONG 消息:PONG 消息封裝了自身狀態(tài)數(shù)據(jù)锦积∶⑴粒可以分為兩種:第一種是在接到 MEET/PING 消息后回復(fù)的 PONG 消息丰介;第二種是指節(jié)點(diǎn)向集群廣播 PONG 消息背蟆。

這樣其他節(jié)點(diǎn)可以獲知該節(jié)點(diǎn)的最新信息,例如故障恢復(fù)后新的主節(jié)點(diǎn)會(huì)廣播 PONG 消息淆储。

FAIL 消息:當(dāng)一個(gè)主節(jié)點(diǎn)判斷另一個(gè)主節(jié)點(diǎn)進(jìn)入 FAIL 狀態(tài)時(shí)冠场,會(huì)向集群廣播這一 FAIL 消息;接收節(jié)點(diǎn)會(huì)將這一 FAIL 消息保存起來(lái)本砰,便于后續(xù)的判斷碴裙。

PUBLISH 消息:節(jié)點(diǎn)收到 PUBLISH 命令后,會(huì)先執(zhí)行該命令点额,然后向集群廣播這一消息舔株,接收節(jié)點(diǎn)也會(huì)執(zhí)行該 PUBLISH 命令。

數(shù)據(jù)結(jié)構(gòu):

節(jié)點(diǎn)需要專門的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)集群的狀態(tài)还棱。所謂集群的狀態(tài)载慈,是一個(gè)比較大的概念,包括:集群是否處于上線狀態(tài)珍手、集群中有哪些節(jié)點(diǎn)办铡、節(jié)點(diǎn)是否可達(dá)、節(jié)點(diǎn)的主從狀態(tài)琳要、槽的分布……

節(jié)點(diǎn)為了存儲(chǔ)集群狀態(tài)而提供的數(shù)據(jù)結(jié)構(gòu)中寡具,最關(guān)鍵的是 clusterNode 和 clusterState 結(jié)構(gòu):前者記錄了一個(gè)節(jié)點(diǎn)的狀態(tài),后者記錄了集群作為一個(gè)整體的狀態(tài)稚补。

clusterNode

clusterNode 結(jié)構(gòu)保存了一個(gè)節(jié)點(diǎn)的當(dāng)前狀態(tài)童叠,包括創(chuàng)建時(shí)間、節(jié)點(diǎn) id课幕、ip 和端口號(hào)等厦坛。

每個(gè)節(jié)點(diǎn)都會(huì)用一個(gè) clusterNode 結(jié)構(gòu)記錄自己的狀態(tài),并為集群內(nèi)所有其他節(jié)點(diǎn)都創(chuàng)建一個(gè) clusterNode 結(jié)構(gòu)來(lái)記錄節(jié)點(diǎn)狀態(tài)乍惊。

下面列舉了 clusterNode 的部分字段杜秸,并說(shuō)明了字段的含義和作用:


集群命令的實(shí)現(xiàn):

這一部分將以 cluster meet(節(jié)點(diǎn)握手)、cluster addslots(槽分配)為例润绎,說(shuō)明節(jié)點(diǎn)是如何利用上述數(shù)據(jù)結(jié)構(gòu)和通信機(jī)制實(shí)現(xiàn)集群命令的撬碟。

cluster meet

假設(shè)要向 A 節(jié)點(diǎn)發(fā)送 cluster meet 命令,將 B 節(jié)點(diǎn)加入到 A 所在的集群凡橱,則 A 節(jié)點(diǎn)收到命令后小作,執(zhí)行的操作如下:

A 為 B 創(chuàng)建一個(gè) clusterNode 結(jié)構(gòu),并將其添加到 clusterState 的 nodes 字典中稼钩。

A 向 B 發(fā)送 MEET 消息顾稀。

B 收到 MEET 消息后,會(huì)為 A 創(chuàng)建一個(gè) clusterNode 結(jié)構(gòu)坝撑,并將其添加到 clusterState 的 nodes 字典中静秆。

B 回復(fù) A 一個(gè) PONG 消息粮揉。

A 收到 B 的 PONG 消息后,便知道 B 已經(jīng)成功接收自己的 MEET 消息抚笔。

然后扶认,A 向 B 返回一個(gè) PING 消息。

B 收到 A 的 PING 消息后殊橙,便知道 A 已經(jīng)成功接收自己的 PONG 消息辐宾,握手完成。

之后膨蛮,A 通過(guò) Gossip 協(xié)議將 B 的信息廣播給集群內(nèi)其他節(jié)點(diǎn)叠纹,其他節(jié)點(diǎn)也會(huì)與 B 握手;一段時(shí)間后敞葛,集群收斂誉察,B 成為集群內(nèi)的一個(gè)普通節(jié)點(diǎn)。

通過(guò)上述過(guò)程可以發(fā)現(xiàn)惹谐,集群中兩個(gè)節(jié)點(diǎn)的握手過(guò)程與 TCP 類似持偏,都是三次握手:A 向 B 發(fā)送 MEET;B 向 A 發(fā)送 PONG氨肌;A 向 B 發(fā)送 PING鸿秆。

cluster addslots:

集群中槽的分配信息,存儲(chǔ)在 clusterNode 的 slots 數(shù)組和 clusterState 的 slots 數(shù)組中儒飒,兩個(gè)數(shù)組的結(jié)構(gòu)前面已做介紹谬莹。

二者的區(qū)別在于:前者存儲(chǔ)的是該節(jié)點(diǎn)中分配了哪些槽檩奠,后者存儲(chǔ)的是集群中所有槽分別分布在哪個(gè)節(jié)點(diǎn)桩了。

cluster addslots 命令接收一個(gè)槽或多個(gè)槽作為參數(shù),例如在 A 節(jié)點(diǎn)上執(zhí)行 cluster addslots {0..10} 命令埠戳,是將編號(hào)為 0-10 的槽分配給 A 節(jié)點(diǎn)井誉。

具體執(zhí)行過(guò)程如下:

遍歷輸入槽,檢查它們是否都沒(méi)有分配整胃,如果有一個(gè)槽已分配颗圣,命令執(zhí)行失敗屁使;方法是檢查輸入槽在 clusterState.slots[] 中對(duì)應(yīng)的值是否為 NULL在岂。

遍歷輸入槽,將其分配給節(jié)點(diǎn) A蛮寂;方法是修改 clusterNode.slots[] 中對(duì)應(yīng)的比特為 1蔽午,以及 clusterState.slots[] 中對(duì)應(yīng)的指針指向 A 節(jié)點(diǎn)。

A 節(jié)點(diǎn)執(zhí)行完成后酬蹋,通過(guò)節(jié)點(diǎn)通信機(jī)制通知其他節(jié)點(diǎn)及老,所有節(jié)點(diǎn)都會(huì)知道 0-10 的槽分配給了 A 節(jié)點(diǎn)抽莱。

客戶端訪問(wèn)集群:

當(dāng)節(jié)點(diǎn)收到 redis-cli 發(fā)來(lái)的命令(如 set/get)時(shí),過(guò)程如下:

①計(jì)算 key 屬于哪個(gè)槽:CRC16(key) &16383骄恶。

集群提供的 cluster keyslot 命令也是使用上述公式實(shí)現(xiàn)食铐,如:

②判斷 key 所在的槽是否在當(dāng)前節(jié)點(diǎn):假設(shè) key 位于第 i 個(gè)槽,clusterState.slots[i] 則指向了槽所在的節(jié)點(diǎn)僧鲁。

如果 clusterState.slots[i]==clusterState.myself虐呻,說(shuō)明槽在當(dāng)前節(jié)點(diǎn),可以直接在當(dāng)前節(jié)點(diǎn)執(zhí)行命令寞秃。

否則铃慷,說(shuō)明槽不在當(dāng)前節(jié)點(diǎn),則查詢槽所在節(jié)點(diǎn)的地址(clusterState.slots[i].ip/port)蜕该,并將其包裝到 MOVED 錯(cuò)誤中返回給 redis-cli犁柜。

③redis-cli 收到 MOVED 錯(cuò)誤后,根據(jù)返回的 ip 和 port 重新發(fā)送請(qǐng)求堂淡。

下面的例子展示了 redis-cli 和集群的互動(dòng)過(guò)程:在 6379 節(jié)點(diǎn)中操作 key1馋缅,但 key1 所在的槽 9189 在節(jié)點(diǎn) 6378 中。

因此節(jié)點(diǎn)返回 MOVED 錯(cuò)誤(包含 6378 節(jié)點(diǎn)的 ip 和 port)給 redis-cli绢淀,redis-cli 重新向 6378 發(fā)起請(qǐng)求萤悴。

上例中,redis-cli 通過(guò) -c 指定了集群模式皆的,如果沒(méi)有指定覆履,redis-cli 無(wú)法處理 MOVED 錯(cuò)誤:

Smart客戶端:

redis-cli 這一類客戶端稱為 Dummy 客戶端,因?yàn)樗鼈冊(cè)趫?zhí)行命令前不知道數(shù)據(jù)在哪個(gè)節(jié)點(diǎn)费薄,需要借助 MOVED 錯(cuò)誤重新定向硝全。與 Dummy 客戶端相對(duì)應(yīng)的是 Smart 客戶端。

②此外楞抡,JedisCluster 為每個(gè)節(jié)點(diǎn)創(chuàng)建連接池(即 JedisPool)伟众。

③當(dāng)執(zhí)行命令時(shí),JedisCluster 根據(jù) key->slot->node 選擇需要連接的節(jié)點(diǎn)召廷,發(fā)送命令凳厢。

如果成功,則命令執(zhí)行完畢竞慢;如果執(zhí)行失敗先紫,則會(huì)隨機(jī)選擇其他節(jié)點(diǎn)進(jìn)行重試,并在出現(xiàn) MOVED 錯(cuò)誤時(shí)筹煮,使用 cluster slots 重新同步 slot->node 的映射關(guān)系遮精。

下面代碼演示了如何使用 JedisCluster 訪問(wèn)集群(未考慮資源釋放、異常處理等):

注意事項(xiàng)如下:

JedisCluster 中已經(jīng)包含所有節(jié)點(diǎn)的連接池寺谤,因此 JedisCluster 要使用單例仑鸥。

客戶端維護(hù)了 slot->node 映射關(guān)系以及為每個(gè)節(jié)點(diǎn)創(chuàng)建了連接池吮播,當(dāng)節(jié)點(diǎn)數(shù)量較多時(shí),應(yīng)注意客戶端內(nèi)存資源和連接資源的消耗眼俊。

Jedis 較新版本針對(duì) JedisCluster 做了一些性能方面的優(yōu)化意狠,如 cluster slots 緩存更新和鎖阻塞等方面的優(yōu)化,應(yīng)盡量使用 2.8.2 及以上版本的 Jedis疮胖。

實(shí)踐需知:

前面介紹了集群正常運(yùn)行和訪問(wèn)的方法和原理环戈,下面是一些重要的補(bǔ)充內(nèi)容。

集群收縮:

實(shí)踐中常常需要對(duì)集群進(jìn)行伸縮澎灸,如訪問(wèn)量增大時(shí)的擴(kuò)容操作院塞。Redis 集群可以在不影響對(duì)外服務(wù)的情況下實(shí)現(xiàn)伸縮;伸縮的核心是槽遷移:修改槽與節(jié)點(diǎn)的對(duì)應(yīng)關(guān)系性昭,實(shí)現(xiàn)槽(即數(shù)據(jù))在節(jié)點(diǎn)之間的移動(dòng)拦止。

例如,如果槽均勻分布在集群的 3 個(gè)節(jié)點(diǎn)中糜颠,此時(shí)增加一個(gè)節(jié)點(diǎn)汹族,則需要從 3 個(gè)節(jié)點(diǎn)中分別拿出一部分槽給新節(jié)點(diǎn),從而實(shí)現(xiàn)槽在 4 個(gè)節(jié)點(diǎn)中的均勻分布其兴。

參考文檔:http://url.cn/5SfYhsC

https://redis.io/topics/cluster-tutorial

https://redis.io/topics/cluster-spec

https://mp.weixin.qq.com/s/d6hzmk31o7VBsMYaLdQ5mw

https://www.cnblogs.com/lpfuture/p/5796398.html

http://www.zsythink.net/archives/1182/

https://www.cnblogs.com/xxdfly/p/5641719.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顶瞒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子元旬,更是在濱河造成了極大的恐慌榴徐,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匀归,死亡現(xiàn)場(chǎng)離奇詭異坑资,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)朋譬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門盐茎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)兴垦,“玉大人徙赢,你說(shuō)我怎么就攤上這事√皆剑” “怎么了狡赐?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)钦幔。 經(jīng)常有香客問(wèn)我枕屉,道長(zhǎng),這世上最難降的妖魔是什么鲤氢? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任搀擂,我火速辦了婚禮西潘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哨颂。我一直安慰自己喷市,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布威恼。 她就那樣靜靜地躺著品姓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪箫措。 梳的紋絲不亂的頭發(fā)上腹备,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音斤蔓,去河邊找鬼植酥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛弦牡,可吹牛的內(nèi)容都是我干的惧互。 我是一名探鬼主播拯刁,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼仪或,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了哩治?” 一聲冷哼從身側(cè)響起稻据,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤艾猜,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后捻悯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匆赃,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年今缚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了算柳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡姓言,死狀恐怖瞬项,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情何荚,我是刑警寧澤囱淋,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站餐塘,受9級(jí)特大地震影響妥衣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一税手、第九天 我趴在偏房一處隱蔽的房頂上張望蜂筹。 院中可真熱鬧,春花似錦芦倒、人聲如沸狂票。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)闺属。三九已至,卻和暖如春周霉,著一層夾襖步出監(jiān)牢的瞬間掂器,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工俱箱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留国瓮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓狞谱,卻偏偏與公主長(zhǎng)得像乃摹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子跟衅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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