redis集群簡述
哨兵模式中如果主從中 master宕機(jī)了,是通過哨兵來選舉出新的master,在這個(gè)選舉切換主從的過程,整個(gè)redis服務(wù)是不可用的。而且哨兵模式中只有一個(gè)主節(jié)點(diǎn)對外提供服務(wù),因此沒法支持更高的并發(fā)。而且當(dāng)個(gè)主節(jié)點(diǎn)的內(nèi)存設(shè)置也不宜過大。否則會導(dǎo)致持久化文件過大,影響數(shù)據(jù)恢復(fù)或主從同步的效率。
redis集群是由 一系列的 主從節(jié)點(diǎn)群組成的分布式服務(wù)器群,它具有復(fù)制、高可用和分片特性。 Redis集群不需要 sentinel哨兵也能完成節(jié)點(diǎn)移除和故障轉(zhuǎn)移的功能。需要將每個(gè)節(jié)點(diǎn)設(shè)置成集群模式,這種集群模式?jīng)]有中心節(jié)點(diǎn) ,客戶端通過 CRC16算法對key進(jìn)行hash
得到一個(gè)值,來判斷該 key存儲在哪個(gè)主從服務(wù)上面,因此就算是某一個(gè)主從整個(gè)宕機(jī),redis集群也是部分可用的。方便 水平擴(kuò)展, 可以根據(jù)業(yè)務(wù)規(guī)模可以隨時(shí)加減配置。 據(jù)官方文檔稱可以線性擴(kuò)展到上萬個(gè)節(jié)點(diǎn) ( 但是 官方推薦不超過 1000個(gè)節(jié)點(diǎn))。redis集群的性能和高可用性均優(yōu)于哨兵模式 。
Redis 集群搭建
1. 修改 redis.conf 配置文件
- daemonize yes 后臺啟動
- cluster-enabled yes 開啟集群模式
- cluster-config-file nodes-6379.conf 集群配置信息存放文件名
- cluster-node-timeout 5000 節(jié)點(diǎn)離線時(shí)間限制,到達(dá)此值時(shí)發(fā)起某個(gè)主從重新選舉 master
- protected-mode no 關(guān)閉保護(hù)模式
- requirepass xxx 設(shè)置本機(jī)密碼
- masterauth xxx 設(shè)置訪問別的機(jī)器的密碼
2. 注意關(guān)閉服務(wù)器的防火墻,否則可能造成節(jié)點(diǎn)之間無法通信,無法搭建集群
使用修改好的配置文件啟動 redis 服務(wù),我這里使用三個(gè)一主一從來搭建。因此先將 6 個(gè) redis 服務(wù)使用指定的配置文件 redis-master.conf 啟動起來: src/redis-server redis-master.conf
3.搭建集群服務(wù)
為了保險(xiǎn)起見最好先檢查下每臺機(jī)器的 redis 服務(wù)是否正常啟動了 ps -ef|grep redis
可以看見 redis 服務(wù)進(jìn)程后面有個(gè) cluster 的標(biāo)志,普通啟動的 redis 服務(wù)是沒有這個(gè)標(biāo)志的
5.0 版本可以直接使用 C 語言客戶端提供的指令去構(gòu)建集群:
src/redis-cli -a xxx --cluster create --cluster-replicas 1 192.168.0.67:6379 192.168.0.68:6379 192.168.0.69:6379 192.168.0.70:6379 192.168.0.71:6379 192.168.0.72:6379
-a 配置的密碼
--cluster create 表示集群創(chuàng)建
--cluster-replicas 表示每個(gè) master 幾個(gè) slave ,上面一共 6 個(gè) redis 節(jié)點(diǎn),因此會構(gòu)建三個(gè)一主一從。
執(zhí)行命令之前,如果你的 redis 環(huán)境以前搭建過主從或者哨兵之類的,數(shù)據(jù)不干凈可能會報(bào)錯(cuò),最好將持久化文件刪掉,然后 flushdb ,將以前臟數(shù)據(jù)清理掉,否則可能出現(xiàn)如下錯(cuò)誤:
正常執(zhí)行會返回一個(gè)集群分配計(jì)劃,我們按照它的計(jì)劃即可:
然后節(jié)點(diǎn)之間就開始通信構(gòu)建集群,最后會看見 16384 個(gè) slots 分配完畢,可以看見構(gòu)建計(jì)劃中有三個(gè) master ,每個(gè) master 都是有指定槽位的。意思就是存入的 key 經(jīng)過 crc16 hash 算法之后得到的值,在哪個(gè)范圍內(nèi),就存儲到那個(gè) redis 主從上面去,這就是 redis 的分片集群模式。
至此集群搭建完畢
4.集群操作
以集群方式連接 redis 客戶端通過 cluster info 查看集群信息,通過 cluster nodes 查看節(jié)點(diǎn)信息
src/redis-cli -a 密碼 -c 集群方式連接
我們設(shè)置 set abc 123 一個(gè)值 會看見客戶點(diǎn)會計(jì)算 abc 的 slot 是 7638 , 然后重定向到對應(yīng)的主從的 master 上面去寫數(shù)據(jù)
現(xiàn)在我看下 JAVA 客戶端的 jedis 里面的 key 值計(jì)算 redis.clients.util.JedisClusterCRC16#getSlot(java.lang.String) :
最后計(jì)算結(jié)果就會落到 0-16383 之間去。
當(dāng) Redis Cluster 的客戶端來連接集群時(shí),它也會得到一份集群的槽位配置信息并將其緩存在客戶端本地。這樣當(dāng)客戶 端要查找某個(gè) key 時(shí),可以直接定位到目標(biāo)節(jié)點(diǎn)。同時(shí)因?yàn)椴畚坏男畔⒖赡軙嬖诳蛻舳伺c服務(wù)器不一致的情況,還需 要糾正機(jī)制來實(shí)現(xiàn)槽位信息的校驗(yàn)調(diào)整。
集中式集群和分片式集群
Redis 節(jié)點(diǎn)之間使用的是 gossip 協(xié)議進(jìn)行通信,每個(gè)節(jié)點(diǎn)之間都會互相通信。
gossip 協(xié)議包含多種消息,包括 ping , pong , meet , fail 等等。
ping :每個(gè)節(jié)點(diǎn)都會頻繁給其他節(jié)點(diǎn)發(fā)送 ping ,其中包含自己的狀態(tài)還有自己維護(hù)的集群元數(shù)據(jù),互相通過 ping 交換元數(shù)據(jù);
pong: 返回 ping 和 meet ,包含自己的狀態(tài)和其他信息,也可以用于信息廣播和更新;
fail: 某個(gè)節(jié)點(diǎn)判斷另一個(gè)節(jié)點(diǎn) fail 之后,就發(fā)送 fail 給其他節(jié)點(diǎn),通知其他節(jié)點(diǎn),指定的節(jié)點(diǎn)宕機(jī)了。
meet :某個(gè)節(jié)點(diǎn)發(fā)送 meet 給新加入的節(jié)點(diǎn),讓新節(jié)點(diǎn)加入集群中,然后新節(jié)點(diǎn)就會開始與其他節(jié)點(diǎn)進(jìn)行通信,不需要發(fā)送形成網(wǎng)絡(luò)的所需的所有 CLUSTER MEET 命令。發(fā)送 CLUSTER MEET 消息以便每個(gè)節(jié)點(diǎn)能夠達(dá)到其他每個(gè)節(jié)點(diǎn)只需通 過一條已知的節(jié)點(diǎn)鏈就夠了。由于在心跳包中會交換 gossip 信息,將會創(chuàng)建節(jié)點(diǎn)間缺失的鏈接。
gossip 協(xié)議的優(yōu)點(diǎn)在于元數(shù)據(jù)的更新比較分散,不是集中在一個(gè)地方,更新請求會陸陸續(xù)續(xù),打到所有節(jié)點(diǎn)上去更新, 有一定的延時(shí),降低了壓力;缺點(diǎn)在于元數(shù)據(jù)更新有延時(shí)可能導(dǎo)致集群的一些操作會有一些滯后。
就是自己提供服務(wù)的端口號 +10000 ,比如 6379 ,那么用于節(jié)點(diǎn)間通信 的就是 16379 端口。 每個(gè)節(jié)點(diǎn)每隔一段時(shí)間都會往另外幾個(gè)節(jié)點(diǎn)發(fā)送 ping 消息,同時(shí)其他幾點(diǎn)接收到 ping 消息之后返回 pong 消息。
還有就是集中式的,比如 ZK 集群
集中式的有點(diǎn)在于數(shù)據(jù)的更新和讀取,時(shí)效性非常好,一旦元數(shù)據(jù)出現(xiàn)變更立即就會更新到集中式( master )的存儲中,其他節(jié)點(diǎn)讀取的 時(shí)候立即就可以立即感知到;不足在于所有的元數(shù)據(jù)的更新壓力全部集中在一個(gè)地方,可能導(dǎo)致元數(shù)據(jù)的存儲壓力。
Redis 集群選舉機(jī)制
當(dāng) slave發(fā)現(xiàn)自己的master變?yōu)镕AIL狀態(tài)時(shí),便嘗試 發(fā)起選舉 ,以期成為新的 master。由于掛掉的master可能會有 多個(gè) slave,從而存在多個(gè)slave競爭成為master節(jié)點(diǎn)的過程, 其過程如下:
1.slave發(fā)現(xiàn)自己的master變?yōu)镕AIL
2.將自己記錄的集群currentEpoch(選舉輪次標(biāo)記)加1,并廣播信息給集群中其他節(jié)點(diǎn)
3.其他節(jié)點(diǎn)收到該信息,只有master響應(yīng),判斷請求者的合法性,并發(fā)送結(jié)果
4.嘗試選舉的slave收集master返回的結(jié)果,收到 超過半數(shù) master的統(tǒng)一 后變成新 Master
5.廣播Pong消息通知其他集群節(jié)點(diǎn)。
如果這次選舉不成功,比如三個(gè)小的主從 A,B,C組成的集群,A的master掛了,A的兩個(gè)小弟發(fā)起選舉,結(jié)果B的master投給A的小弟A1,C的master投給了A的小弟A2,這樣就會發(fā)起第二次選舉,選舉輪次標(biāo)記+1繼續(xù)上面的流程。事實(shí)上從節(jié)點(diǎn)并不是在主節(jié)點(diǎn)一進(jìn)入 FAIL 狀態(tài)就馬上嘗試發(fā)起選舉,而是有一定延遲,一定的延遲確保我們等待FAIL狀態(tài)在集群中傳播,slave如果立即嘗試選舉,其它masters或許尚未意識到FAIL狀態(tài),可能會拒絕投票。 同時(shí)下面公式里面的隨機(jī)數(shù),也可以有效避免slave同時(shí)發(fā)起選舉,導(dǎo)致的平票情況。
•延遲計(jì)算公式:
DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
•SLAVE_RANK表示此slave已經(jīng)從master復(fù)制數(shù)據(jù)的總量的rank。Rank越小代表已復(fù)制的數(shù)據(jù)越新。這種方式下,持有最新數(shù)據(jù)的slave將會首先發(fā)起選舉(理論上)。
前面說到這種分片的集群模式的集群可以部分提供服務(wù), 當(dāng) redis.conf的配置cluster-require-full-coverage為no時(shí), 表示當(dāng)一個(gè)小主從整體掛掉的時(shí)候集群也可以用,也是說 0-16383個(gè)槽位中,落在該主從對應(yīng)的slots上面的key是用不了的,但是如果key落在其他的范圍是仍然可用的。