前言
哨兵模式雖然讓讀寫分離更加高可用毁枯,但單臺(tái)服務(wù)器由于本身的內(nèi)存和CPU瓶頸慈缔,對(duì)于高并發(fā)和大數(shù)據(jù)業(yè)務(wù)的應(yīng)用場(chǎng)景還是遠(yuǎn)遠(yuǎn)不能滿足;對(duì)于這種情況种玛,有點(diǎn)經(jīng)驗(yàn)的小伙伴會(huì)毫不猶豫的想到集群藐鹤,搞他好幾個(gè)節(jié)點(diǎn),負(fù)載均衡再加上故障轉(zhuǎn)移赂韵,豈不美哉娱节。是的,就是這個(gè)理祭示,接下來玩玩肄满。
正文
集群,相信這個(gè)詞小伙伴應(yīng)該聽的耳朵起繭子了吧质涛;多搞幾臺(tái)服務(wù)器稠歉,讓請(qǐng)求/命令平均分發(fā)到各個(gè)服務(wù)器,避免單臺(tái)服務(wù)器承載過大壓力汇陆;對(duì)于Redis集群來說轧抗,為了實(shí)現(xiàn)自動(dòng)故障轉(zhuǎn)移,還需要在每個(gè)主節(jié)點(diǎn)上增加一個(gè)或多個(gè)從節(jié)點(diǎn)瞬测,當(dāng)主節(jié)點(diǎn)發(fā)生故障時(shí)横媚,從節(jié)點(diǎn)自動(dòng)補(bǔ)上,實(shí)現(xiàn)高可用月趟。
總的來說灯蝴,Redis集群有以下作用:
- 多主節(jié)點(diǎn)的實(shí)現(xiàn)可以應(yīng)對(duì)高并發(fā)場(chǎng)景,并發(fā)量增大孝宗,節(jié)點(diǎn)可以隨時(shí)擴(kuò)展?jié)M足需求穷躁;
- 多主節(jié)點(diǎn)的實(shí)現(xiàn)可以存儲(chǔ)更多的數(shù)據(jù),因?yàn)閿?shù)據(jù)均勻分布到各個(gè)節(jié)點(diǎn)因妇;
- 多主節(jié)點(diǎn)搭配多從節(jié)點(diǎn)的實(shí)現(xiàn)讓高可用更加穩(wěn)定问潭,即當(dāng)有主節(jié)點(diǎn)發(fā)生故障時(shí),對(duì)應(yīng)下面的從節(jié)點(diǎn)會(huì)升級(jí)為主節(jié)點(diǎn)婚被,正常提供功能狡忙;
老規(guī)矩不變,一邊實(shí)操一邊總結(jié)址芯,接下來搭建一個(gè)3主3從的集群灾茁,這是最簡(jiǎn)單的窜觉。 Redis集群中最少需要3個(gè)主節(jié)點(diǎn),再加上為了實(shí)現(xiàn)高可用北专,每個(gè)主節(jié)點(diǎn)至少得跟一個(gè)從節(jié)點(diǎn)禀挫,不然一個(gè)主節(jié)點(diǎn)掛了,找不到完整的數(shù)據(jù)拓颓,整個(gè)集群就不能用了语婴;至于為什么會(huì)找不到完整的數(shù)據(jù),下面會(huì)聊到驶睦。
接下來要搭建的集群環(huán)境如下:
簡(jiǎn)要說明:
- 6370為主節(jié)點(diǎn)腻格,6381為6370的從節(jié)點(diǎn);
- 6380為主節(jié)點(diǎn)啥繁,6391為6380的從節(jié)點(diǎn)菜职;
- 6390為主節(jié)點(diǎn),6371為6390的從節(jié)點(diǎn)旗闽;
- 在集群環(huán)境中主節(jié)點(diǎn)之間是相互通訊的(這里沒有哨兵)酬核,每一個(gè)節(jié)點(diǎn)都是數(shù)據(jù)節(jié)點(diǎn);
這里集群方案使用redis-cli自動(dòng)指定主從關(guān)系(小伙伴的主從關(guān)系可能會(huì)和我這不一樣哦)适室,也可以手動(dòng)指定嫡意;反正思路都一樣;
以下演示在同一臺(tái)機(jī)器上捣辆,通過端口區(qū)分各個(gè)節(jié)點(diǎn)蔬螟;在實(shí)際開發(fā)中,一般都是用不同的服務(wù)器汽畴。
案例演示
-
準(zhǔn)備六個(gè)節(jié)點(diǎn)的配置文件旧巾,開啟集群相關(guān)配置;
拷貝最初默認(rèn)的配置文件忍些,然后進(jìn)行更改鲁猩,主要更改以下項(xiàng):
port 6370 # 指定Redis節(jié)點(diǎn)端口 pidfile /var/run/redis_6370.pid # 指定對(duì)應(yīng)進(jìn)程文件 dbfilename dump6370.rdb # 每個(gè)節(jié)點(diǎn)的rdb持久化文件 cluster-enabled yes # 開啟集群,這個(gè)比較重要 cluster-config-file nodes-6370.conf #指定每個(gè)節(jié)點(diǎn)的集群配置文件罢坝,這個(gè)比較重要
以上配置文件內(nèi)容在其他節(jié)點(diǎn)(6370,6371,6380,6381,6390,6391)都需要進(jìn)行修改廓握,只是將其中6370改為對(duì)應(yīng)節(jié)點(diǎn)的端口即可,目的就是為了不同節(jié)點(diǎn)使用不同端口并區(qū)分用到的不同文件即可嘁酿;比如需要修改6371節(jié)點(diǎn)的配置文件如下:
port 6371 # 指定Redis節(jié)點(diǎn)端口 pidfile /var/run/redis_6371.pid # 指定對(duì)應(yīng)進(jìn)程文件 dbfilename dump6371.rdb # 每個(gè)節(jié)點(diǎn)的rdb持久化文件 cluster-enabled yes # 開啟集群隙券,這個(gè)比較重要 cluster-config-file nodes-6371.conf #指定每個(gè)節(jié)點(diǎn)的集群配置文件,這個(gè)比較重要
其中cluster-enabled和cluster-config-file是集群配置的重點(diǎn)闹司。
-
啟動(dòng)六個(gè)節(jié)點(diǎn)娱仔,剛開始各個(gè)節(jié)點(diǎn)是相互獨(dú)立的;
準(zhǔn)備好配置文件之后开仰,就可以使用redis-server指定配置文件啟動(dòng)節(jié)點(diǎn)啦剃根,如果節(jié)點(diǎn)多搞莺,小伙伴可以編寫腳本哦;
./redis-server ZoeCluster/redis6370.conf # 啟動(dòng)6370節(jié)點(diǎn) ./redis-server ZoeCluster/redis6371.conf # 啟動(dòng)6371節(jié)點(diǎn) ./redis-server ZoeCluster/redis6380.conf # 啟動(dòng)6380節(jié)點(diǎn) ./redis-server ZoeCluster/redis6381.conf # 啟動(dòng)6381節(jié)點(diǎn) ./redis-server ZoeCluster/redis6390.conf # 啟動(dòng)6390節(jié)點(diǎn) ./redis-server ZoeCluster/redis6391.conf # 啟動(dòng)6391節(jié)點(diǎn)
啟動(dòng)效果如下:
image-20210202110403525這樣只是將各個(gè)節(jié)點(diǎn)啟動(dòng)起來,集群關(guān)系還沒創(chuàng)建呢二庵,如果不信,可以使用redis-cli連接任意一個(gè)節(jié)點(diǎn)查看集群信息梅尤,如下:
image-20210201232539758如上圖替劈,cluster-size為0,集群的關(guān)鍵滨达,槽也還沒有分配奶稠;那接下來肯定是要將各節(jié)點(diǎn)的集群關(guān)系搞起來;
-
建立節(jié)點(diǎn)集群關(guān)系
由于我使用的Redis版本是5.0捡遍,直接可以使用redis-cli就可以進(jìn)行集群搭建锌订,在此版本之前都推薦使用redis-trib.rb進(jìn)行相關(guān)操作,這個(gè)是一個(gè)Ruby腳本画株,需要安裝相關(guān)環(huán)境辆飘,小伙伴可以下來嘗試;
使用命令如下:
./redis-cli --cluster create --cluster-replicas 1 127.0.0.1:6370 127.0.0.1:6380 127.0.0.1:6390 127.0.0.1:6371 127.0.0.1:6381 127.0.0.1:6391
參數(shù)簡(jiǎn)介:
-- cluster : 指定是用于創(chuàng)建集群環(huán)境谓传;
-a:密碼蜈项,即如果有密碼,可以通過-a傳參续挟,這里沒有設(shè)置密碼紧卒;
--cluster-replicas:這里設(shè)置為1, 用于配置主節(jié)點(diǎn)上的從節(jié)點(diǎn)數(shù),1就代表一主一從诗祸,2就代表一主二從跑芳,依次類推;
后面的是節(jié)點(diǎn)IP:節(jié)點(diǎn)端口直颅,一般前面的是主節(jié)點(diǎn)聋亡,后面的是從節(jié)點(diǎn);
image-20210201233838902如果同意集群方案际乘,然后就開始進(jìn)行相關(guān)操作坡倔,如下:
image-20210201234435208同樣,可以連接到任意一個(gè)節(jié)點(diǎn)脖含,查看集群情況罪塔,如下:
image-20210201235503407注:關(guān)于主從節(jié)點(diǎn)之間的主從復(fù)制過程就不在這說了,和之前說過的主從復(fù)制一樣养葵;
-
演示訪問操作征堪;
使用redis-cli連接任意節(jié)點(diǎn)寫入數(shù)據(jù),如果不指定集群連接的話关拒,會(huì)寫入數(shù)據(jù)失敗佃蚜,如下:
image-20210202000216157由于集群環(huán)境下庸娱,數(shù)據(jù)的存儲(chǔ)位置是根據(jù)Key來計(jì)算而來的(這里牽涉到一致性哈希算法),使得數(shù)據(jù)可以均勻分配到各節(jié)點(diǎn)上谐算,所以在redis-cli連接的時(shí)候需要指定集群模式熟尉,如下:
image-20210202000548069如上圖所示,指定集群模式之后就可以正常存取了洲脂;
-
故障演示
既然集群環(huán)境斤儿,肯定少不了要好好測(cè)測(cè);
模擬從節(jié)點(diǎn)掛掉
找個(gè)從節(jié)點(diǎn)停掉試試恐锦,這里停掉6371節(jié)點(diǎn)往果,根據(jù)創(chuàng)建集群信息知道,它的主節(jié)點(diǎn)是6390一铅;
主節(jié)點(diǎn)顯示從節(jié)點(diǎn)斷開連接陕贮,看看它的主節(jié)點(diǎn)反應(yīng):
image-20210202001617324其他集群節(jié)點(diǎn)只是將從節(jié)點(diǎn)標(biāo)記為failing狀態(tài),即下線狀態(tài)潘飘,如下:
image-20210202001759260對(duì)于存取數(shù)據(jù)也不受影響肮之,這里就不截圖了,小伙伴自行嘗試吧福也;
當(dāng)故障的從節(jié)點(diǎn)6371重新連上時(shí)局骤,主節(jié)點(diǎn)恢復(fù)主從關(guān)系,并進(jìn)行主從復(fù)制操作暴凑;其他集群節(jié)點(diǎn)會(huì)清除原來標(biāo)記的下線狀態(tài)峦甩,將其改為上線;
模擬主節(jié)點(diǎn)掛掉
這里就手動(dòng)將6390這個(gè)節(jié)點(diǎn)停掉现喳,會(huì)有怎樣的反應(yīng)呢凯傲?
自身從節(jié)點(diǎn)會(huì)每隔一秒檢測(cè)連接,如果超時(shí)(默認(rèn)是15秒)嗦篱,會(huì)選舉從節(jié)點(diǎn)做為集群的主節(jié)點(diǎn)來提供服務(wù)冰单,如下圖:
image-20210202003020600數(shù)據(jù)存取最終還是不受影響;
對(duì)于其他集群節(jié)點(diǎn)灸促,將故障節(jié)點(diǎn)標(biāo)記為failing诫欠,讓新上任的主節(jié)點(diǎn)提供服務(wù),如下圖:
image-20210202003343926存取數(shù)據(jù)也是不受影響的浴栽;
掛掉的主節(jié)點(diǎn)6390如果恢復(fù)荒叼,那它只能變?yōu)?371的從節(jié)點(diǎn)啦,并進(jìn)行相關(guān)主從復(fù)制操作典鸡;而集群的其他節(jié)點(diǎn)只是將其原有的Fail狀態(tài)清除被廓,表示可以正常連接;
Redis集群就是這樣簡(jiǎn)單萝玷,只要思路對(duì)嫁乘,就是手工活昆婿;小伙伴可以編寫腳本自動(dòng)執(zhí)行哦;
接下來說說集群數(shù)據(jù)的存儲(chǔ)蜓斧;
數(shù)據(jù)存儲(chǔ)簡(jiǎn)單分析
在Redis集群環(huán)境中仓蛆,數(shù)據(jù)的存儲(chǔ)位置是根據(jù)對(duì)Key的Hash計(jì)算進(jìn)行指定的; Redis集群為了在節(jié)點(diǎn)改變時(shí)保證數(shù)據(jù)分布均勻法精,引入了槽(slot)作為遷移的基本單位多律,槽解耦了數(shù)據(jù)和實(shí)際節(jié)點(diǎn)的關(guān)系痴突,使得實(shí)際節(jié)點(diǎn)數(shù)的改變對(duì)系統(tǒng)影響較新选;
在整個(gè)集群中辽装,槽(slot)總共有16384帮碰,會(huì)將其均勻分配到集群的主節(jié)點(diǎn)上,其中每一份槽對(duì)應(yīng)一個(gè)存儲(chǔ)空間(這里的存儲(chǔ)空間可以理解為一個(gè)容器拾积,是可以存很多數(shù)據(jù)的)殉挽,以上集群環(huán)境的槽分配如下:
存儲(chǔ)數(shù)據(jù)的過程,如下:
連接6380主節(jié)點(diǎn)拓巧,執(zhí)行如下操作:
具體過程如下:
簡(jiǎn)要說明:
- 客戶端發(fā)起命令斯碌;
- 服務(wù)器將Key進(jìn)行CRC16計(jì)算,并與總槽位計(jì)算出Key需要存儲(chǔ)的位置肛度;
- 這里模擬的Key為zoe傻唾,計(jì)算出的槽位為14588,不在6380這個(gè)節(jié)點(diǎn)上承耿,集群節(jié)點(diǎn)會(huì)將其重定向到對(duì)應(yīng)槽位的節(jié)點(diǎn)上冠骄;
- 然后找到6371上的14588槽位進(jìn)行數(shù)據(jù)存儲(chǔ);(注加袋,這里的6371已經(jīng)是主節(jié)點(diǎn)了凛辣,因?yàn)樯厦孀鲞^一次故障轉(zhuǎn)移模擬);
那集群節(jié)點(diǎn)是如何知道其他節(jié)點(diǎn)的槽范圍和其他信息呢职烧?
那是因?yàn)楦鞴?jié)點(diǎn)之間有通訊扁誓,通訊端口是對(duì)應(yīng)的redis端口+10000,比如節(jié)點(diǎn)6371的集群通訊端口為16371(如果多臺(tái)機(jī)器蚀之,別忘了防火墻放開這個(gè)端口哦)蝗敢,可以通過cluster nodes看到,如下:
并且將各節(jié)點(diǎn)的信息保存在自己對(duì)應(yīng)的集群配置文件中恬总,這個(gè)集群文件名是通過配置項(xiàng)cluster-config-file指定的前普,在集群節(jié)點(diǎn)啟動(dòng)時(shí)會(huì)檢查該文件是否存在,如果不存在壹堰,會(huì)自動(dòng)創(chuàng)建拭卿,如果存在骡湖,就加載里面的相關(guān)配置信息;里面有哪些信息峻厚,隨便找個(gè)節(jié)點(diǎn)的配置文件看一下:
如上圖所示响蕴,各節(jié)點(diǎn)的配置文件中記錄了其他節(jié)點(diǎn)的主從關(guān)系,分配的槽位惠桃,各節(jié)點(diǎn)的狀態(tài)浦夷;這樣的話,集群關(guān)系就算重新啟動(dòng)也還存在辜王。
集群伸縮(節(jié)點(diǎn)增刪)演示
在實(shí)際應(yīng)用場(chǎng)景中劈狐,會(huì)根據(jù)業(yè)務(wù)需要,對(duì)集群進(jìn)行伸縮呐馆,即節(jié)點(diǎn)的增刪肥缔;業(yè)務(wù)并發(fā)大了加節(jié)點(diǎn)進(jìn)行擴(kuò)展, 節(jié)點(diǎn)需要調(diào)整時(shí)可能需要進(jìn)節(jié)點(diǎn)刪除汹来;
加節(jié)點(diǎn)
這里進(jìn)行節(jié)點(diǎn)擴(kuò)展续膳,加一個(gè)6360主節(jié)點(diǎn),6361作為6360的從節(jié)點(diǎn)收班;參照以上集群搭建時(shí)配置文件更改坟岔,然后將其都啟動(dòng),如下:
6360節(jié)點(diǎn)
port 6360 # 指定Redis節(jié)點(diǎn)端口
pidfile /var/run/redis_6360.pid # 指定對(duì)應(yīng)進(jìn)程文件
dbfilename dump6360.rdb # 每個(gè)節(jié)點(diǎn)的rdb持久化文件
cluster-enabled yes # 開啟集群摔桦,這個(gè)比較重要
cluster-config-file nodes-6360.conf #指定每個(gè)節(jié)點(diǎn)的集群配置文件社付,這個(gè)比較重要
6361節(jié)點(diǎn)
port 6361 # 指定Redis節(jié)點(diǎn)端口
pidfile /var/run/redis_6361.pid # 指定對(duì)應(yīng)進(jìn)程文件
dbfilename dump6361.rdb # 每個(gè)節(jié)點(diǎn)的rdb持久化文件
cluster-enabled yes # 開啟集群,這個(gè)比較重要
cluster-config-file nodes-6361.conf #指定每個(gè)節(jié)點(diǎn)的集群配置文件酣溃,這個(gè)比較重要
兩個(gè)節(jié)點(diǎn)都啟動(dòng)瘦穆,然后將6360加入到集群主節(jié)點(diǎn)中,執(zhí)行以下命令:
./redis-cli --cluster add-node 127.0.0.1:6360 127.0.0.1:6370
注:其中127.0.0.1:6360是需要加入的新增節(jié)點(diǎn)赊豌,127.0.0.1:6370是現(xiàn)有集群中的任意一個(gè)節(jié)點(diǎn)扛或;
可以通過以下命令檢測(cè)集群狀態(tài),如下:
./redis-cli --cluster check 127.0.0.1:6370 # 后面的地址是任意的集群節(jié)點(diǎn)
可以看到6360已經(jīng)加入到集群環(huán)境中碘饼,但現(xiàn)在還沒有從節(jié)點(diǎn)和槽分配熙兔,所以接下來先將6361作為6360的從節(jié)點(diǎn)加入,如下:
./redis-cli --cluster add-node --cluster-slave --cluster-master-id eaa814dc56beb0d5edb6a4fbb14f1384e78d4764 127.0.0.1:6361 127.0.0.1:6370
參數(shù)說明:
- --cluster-slave : 意思就是加入的是從節(jié)點(diǎn)艾恼;
- --cluster-master-id:后面緊跟主節(jié)點(diǎn)的id住涉,這里就是6360的節(jié)點(diǎn)id;通過cluster nodes可以查看到節(jié)點(diǎn)id钠绍;
- 127.0.0.1:6361:需要加入的從節(jié)點(diǎn)舆声;
- 127.0.0.1:6370:現(xiàn)有集群的任意主節(jié)點(diǎn);
現(xiàn)在還差槽分配了,如果需要直接將16384個(gè)槽平均分配到所有節(jié)點(diǎn)話媳握,直接執(zhí)行以下命令即可:
./redis-cli --cluster rebalance --cluster-threshold 1 --cluster-use-empty-masters 127.0.0.1:6370
使用命令./redis-cli --cluster check 127.0.0.1:6370查看分配結(jié)果碱屁,如下圖,只截了部分:
如果不想均勻分配蛾找,根據(jù)自定義需要進(jìn)行配置娩脾,可以執(zhí)行以下命令,會(huì)提示一步一步配置打毛;
./redis-cli --cluster reshard 127.0.0.1:6360 #后面是新加入的主節(jié)點(diǎn)
# 也可以執(zhí)行以下指令直接配置想要的數(shù)據(jù)
./redis-cli --cluster reshard --cluster-from all --cluster-to 需要分配槽的節(jié)點(diǎn)id --cluster-slots 1000 --cluster-yes 127.0.0.1:6370 # 1000 指分配的槽數(shù)
這里就不截圖演示了柿赊,留給小伙伴自己動(dòng)手操作吧;
刪除節(jié)點(diǎn)
先對(duì)節(jié)點(diǎn)進(jìn)行分片工作幻枉,防止數(shù)據(jù)丟失碰声,即將指定節(jié)點(diǎn)上的槽分配到其他節(jié)點(diǎn);
./redis-cli --cluster reshard 要?jiǎng)h除節(jié)點(diǎn)ip:port
-
移除節(jié)點(diǎn)展辞,推薦先刪除從節(jié)點(diǎn)奥邮,再刪除主節(jié)點(diǎn)万牺;
./redis-cli --cluster del-node 節(jié)點(diǎn)ip:port 節(jié)點(diǎn)id
集群配置項(xiàng)
- cluster-enabled(是否開啟集群模式):設(shè)置為yes罗珍,將該節(jié)點(diǎn)開啟為集群模式;
- cluster-config-file(設(shè)置每個(gè)集群節(jié)點(diǎn)對(duì)應(yīng)的配置文件名稱):文件是自動(dòng)生成的脚粟,不用手動(dòng)創(chuàng)建覆旱;
- cluster-node-timeout(設(shè)置超時(shí)時(shí)間,即集群節(jié)點(diǎn)不可用的最大時(shí)間核无,如果超過這個(gè)時(shí)間就認(rèn)為該節(jié)點(diǎn)不可用):默認(rèn)為15000(以毫秒為單位)扣唱;
- cluster-migration-barrier(配置一個(gè)主機(jī)最少可用的從機(jī)的個(gè)數(shù)):默認(rèn)是1,表示一個(gè)主機(jī)的從機(jī)遷移之后,至少得有一個(gè)從機(jī)可用团南,否則不進(jìn)行節(jié)點(diǎn)遷移噪沙;
- cluster-require-full-coverage(配置集群服務(wù)的可用性):默認(rèn)yes開啟,即集群沒完全覆蓋所有slot吐根,集群就掛了正歼;設(shè)置為no,就算槽沒有全分配拷橘,也能提供服務(wù)局义,需要自己保證槽分配;
總結(jié)
到這集群的搭建就完啦冗疮,本來想著寫著很簡(jiǎn)單的萄唇,沒想到又干了4000字;對(duì)于集群术幔,使用有一些限制另萤,比如Keys命令只能針對(duì)當(dāng)前節(jié)點(diǎn),需要針對(duì)多節(jié)點(diǎn)的情況進(jìn)行處理诅挑;集群中各節(jié)點(diǎn)只支持db0數(shù)據(jù)庫四敞,其他數(shù)據(jù)庫不支持等等勾缭;所以使用要注意哦,后續(xù)抽時(shí)間單獨(dú)整理一篇注意事項(xiàng)吧目养,篇幅有點(diǎn)長(zhǎng)俩由,不繼續(xù)聊啦; 下篇說說熟悉的緩存穿透癌蚁、緩存擊穿幻梯、緩存雪崩吧;
一個(gè)被程序搞丑的帥小伙努释,關(guān)注"Code綜藝圈"碘梢,跟我一起學(xué)~~~