Redis Cluster是redis3.0後正式推出的分佈式解決方案。node
以前介紹了複製和哨兵,解決了高可用問題,經過複製,讀操做能夠分發到多個節點(讀實現了負載均衡),可是寫操做依然只有一個節點,沒法實現寫操做的負載均衡,可是依然面臨單機內存和併發的瓶頸。redis
集羣就是用來解決寫操做負載均衡的問題。其核心有兩個做用shell
常見哈希分區主要兩種:數據庫
N爲節點的數量。這種方案優勢是簡單,缺點是當有節點數量變化(擴容or縮容),數據節點映射關係須要從新計算,會致使數據從新遷移。併發
通常用於節點能夠預估不變的場景,好比數據庫分表分庫,好比訂單庫能夠分64個,orderId mod 64可獲得這個訂單數據應該寫入那個庫。負載均衡
實現思路是爲系統中的每個節點分配一個token,範圍通常爲0~2的32次方,這個這些token構成一個哈希環。分佈式
當有數據寫入時,先根據key計算出哈希值X,而後順時針尋找到第一個大於X的token的節點,而後把值存入該節點便可。下圖中:函數
一致性哈希分區中,若是增長或者減小節點,隻影響節點改節點相鄰的節點,其餘節點毫無影響,好比在node1以前增長一個節點,只會使得原來存儲到node1的數據一部分數據(好比A)轉移到新節點,其餘節點毫無影響。3d
一致性哈希的最大問題是,當節點比較少時,新增或者刪除節點會致使數據的分配嚴重不均衡。 在上圖中,若是刪除node1和node2:code
虛擬槽分區是對一致性哈希的改進,用來解決負載均衡的問題。
Redis Cluster採用虛擬槽分區,槽是介於實際節點和數據之間的虛擬概念,每一個節點對應必定範圍的槽,每一個槽包含必定範圍內的哈希值,使用了虛擬槽分區後,數據的映射關係從hash-》節點變成了hash-》槽-》節點。
Redis Cluster槽的範圍是16384(016383)。全部鍵基於哈希函數映射到016383整數槽內(CRC取模),計算公式:
示意圖以下:
使用虛擬槽分區後,節點的變更對系統影響較小,好比上圖中,刪除node1,只須要對0-3276的槽從新分配便可。
搭建一個三主三從的集羣,在同一臺機器上,由端口號進行區分。
7000節點配置以下:
#端口號 port 7000 #開啓集羣模式 cluster-enabled yes #節點超時時間(毫秒) cluster-node-timeout 15000 #集羣內部配置文件 cluster-config-file "nodes-7000.conf" logfile "log-7000.log" protected-mode no daemonize yes
依次配置7001,7002,8000,8001,8002。
啓動6個節點:
src/redis-server redis-7000.conf src/redis-server redis-7001.conf src/redis-server redis-7002.conf src/redis-server redis-8000.conf src/redis-server redis-8001.conf src/redis-server redis-8002.conf
配置相關說明
上面的配置中cluster-enabled 和cluster-config-file是集羣相關的配置。
cluster-enabled 設置爲yes,表明集羣模式,默認redis是單機模式。
cluster-config-file是集羣特有的配置文件,在redis啓動的時候若是發現沒有配置文件會自動建立一個配置文件。
打開配置文件,若是集羣配置文件已經存在,則直接讀取。集羣配置文件由redis自動維護,無需手動修改。
7000首次啓動後生成的集羣配置文件以下:
877e9d061f80cea70285e823cbc4246041752149 :7000@17000 myself,master - 0 0 0 connected 5474 5798 11459 11958 12706 13735 vars currentEpoch 0 lastVoteEpoch 0
記錄了集羣的初始狀態,最重要的是第一個40位的16進制字符串,是集羣的節點ID,節點ID在集羣初始化的時候只建立一次,重啓後會加載集羣配置文件進行重用。集羣節點ID不用於redis的運行id,運行id每次重啓後都會變好。
直接使用redis-cli
命令來建立(redis5.0以後)
輸入命令
redis-cli --cluster create 192.168.118.129:7000 192.168.118.129:7001 192.168.118.129:7002 192.168.118.129:8000 192.168.118.129:8001 192.168.118.129:8002 --cluster-replicas 1
--cluster-replicas 1
表示每個主節點分配一個從節點。
(上面的warning是由於我把全部節點部署到了同一個機器)
輸入yes繼續
集羣配置成功,16384個slots分配完畢。
總體結構
Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 192.168.118.129:8001 to 192.168.118.129:7000 Adding replica 192.168.118.129:8002 to 192.168.118.129:7001 Adding replica 192.168.118.129:8000 to 192.168.118.129:7002
用上面命令建立的集羣是沒法手工指定主從關係的。
Redis採用Gossip協議(P2P),Gossip協議的工做原理就是節點之間不斷通訊交換信息,一段時間後全部節點都會知道集羣的完整信息,相似於流言傳播,相似於下圖:
通訊過程:
Gossip消息類型:
Gossip消息解析流程:
meet
上面的Gossip消息中,ping/pong消息都須要攜帶當前節點的信息和部分其餘節點的信息(狀態等),這些頻繁的信息交換勢必會加劇帶寬和計算負擔。依次每次選擇多少個節點進行通訊(每次要發給多少個節點)變得特別重要:
具體選擇:
選擇發送節點
5個節點是指集羣內隨機找5個節點,取其中一個其餘節點發送ping。
10次:針對上一步選出來的一個節點每100毫秒掃描一次本地的節點列表,若是發現節點最近一次接受pong消息的時間大於cluster-node-timeout/2 ,則須要給該節點發送ping消息,總節點數量:
ping消息數量
自身節點數量+1/10其餘節點的數量
因而可知,節點的cluster_node_timeout和整個集羣節點的數量都會影響集羣節點之間的信息交換。