1. 程式人生 > 實用技巧 >Java必知必會-Redis分散式應用

Java必知必會-Redis分散式應用

分散式解決方案redis cluster

使用原因

1.主從複製不能實現高可用

2.隨著公司發展,使用者數量增多,併發越來越多,業務需要更高的QPS,而主從複製中單機的QPS可能無法滿足業務需求

3.資料量的考慮,現有伺服器記憶體不能滿足業務資料的需要時,單純向伺服器新增記憶體不能達到要求,此時需要考慮分散式需求,把資料分佈到不同伺服器上

4.網路流量需求:業務的流量已經超過伺服器的網絡卡的上限值,可以考慮使用分散式來進行分流

5.離線計算,需要中間環節緩衝等別的需求

資料分佈

順序分佈

比如:1到100個數字,要儲存在3個節點上,按照順序分割槽,把資料平均分配三個節點上 1號到33號資料儲存到節點1上,34號到66號資料儲存到節點2上,67號到100號資料儲存到節點3上。一般常用在關係型資料庫

雜湊分佈

1、節點取餘分割槽:

比如有100個數據,對每個資料進行hash運算之後,與節點數進行取餘運算,根據餘數不同儲存在不同的節點上

節點取餘分割槽方式有一個問題:即當增加或減少節點時,原來節點中的80%的資料會進行遷移操作,對所有資料重新進行分佈

節點取餘分割槽方式建議使用多倍擴容的方式,例如以前用3個節點儲存資料,擴容為比以前多一倍的節點即6個節點來儲存資料,這樣只需要適移50%的資料。資料遷移之後,第一次無法從快取中讀取資料,必須先從資料庫中讀取資料,然後回寫到快取中,然後才能從快取中讀取遷移之後的資料

2、一致性雜湊分割槽

原理:將所有的資料當做一個token環,token環中的資料範圍是0到2的32次方。然後為每一個數據節點分配一個token範圍值,這個節點就負責儲存這個範圍內的資料。一致性雜湊一般用在節點比較多的時候

對每一個key進行hash運算,被雜湊後的結果在哪個token的範圍內,則按順時針去找最近的節點,這個key將會被儲存在這個節點上。

在上面的圖中,有4個key被hash之後的值在在n1節點和n2節點之間,按照順時針規則,這4個key都會被儲存在n2節點上,
如果在n1節點和n2節點之間新增n5節點,當下次有key被hash之後的值在n1節點和n5節點之間,這些key就會被儲存在n5節點上面了
在上面的例子裡,新增n5節點之後,資料遷移會在n1節點和n2節點之間進行,n3節點和n4節點不受影響,資料遷移範圍被縮小很多

同理,如果有1000個節點,此時新增一個節點,受影響的節點範圍最多隻有千分之2
一致性雜湊一般用在節點比較多的時候

一致性雜湊分割槽優點:

採用客戶端分片方式:雜湊 + 順時針(優化取餘)
節點伸縮時,隻影響鄰近節點,但是還是有資料遷移

一致性雜湊分割槽缺點:

翻倍伸縮,保證最小遷移資料和負載均衡

3、虛擬槽分割槽
虛擬槽分割槽是Redis Cluster採用的分割槽方式

預設虛擬槽,每個槽就相當於一個數字,有一定範圍。每個槽對映一個數據子集,一般比節點數大

Redis Cluster中預設虛擬槽的範圍為0到16383

步驟:

1.把16384槽按照節點數量進行平均分配,由節點進行管理
2.對每個key按照CRC16規則進行hash運算
3.把hash結果對16383進行取餘
4.把餘數傳送給Redis節點
5.節點接收到資料,驗證是否在自己管理的槽編號的範圍
    如果在自己管理的槽編號範圍內,則把資料儲存到資料槽中,然後返回執行結果
    如果在自己管理的槽編號範圍外,則會把資料傳送給正確的節點,由正確的節點來把資料儲存在對應的槽中

需要注意的是:Redis Cluster的節點之間會共享訊息,每個節點都會知道是哪個節點負責哪個範圍內的資料槽

虛擬槽分佈方式中,由於每個節點管理一部分資料槽,資料儲存到資料槽中。當節點擴容或者縮容時,對資料槽進行重新分配遷移即可,資料不會丟失。
虛擬槽分割槽特點:

使用服務端管理節點,槽,資料:例如Redis Cluster
可以對資料打散,又可以保證資料分佈均勻

基本架構

節點

Redis Cluster是分散式架構:即Redis Cluster中有多個節點,每個節點都負責進行資料讀寫操作

每個節點之間會進行通訊。

meet操作

節點之間會相互通訊,每個節點裡都有對應的一定數量的槽

meet操作是節點之間完成相互通訊的基礎,meet操作有一定的頻率和規則

分配槽

把16384個槽平均分配給節點進行管理,每個節點只能對自己負責的槽進行讀寫操作

由於每個節點之間都彼此通訊,每個節點都知道另外節點負責管理的槽範圍

客戶端訪問任意節點時,對資料key按照CRC16規則進行hash運算,然後對運算結果對16383進行取餘,如果餘數在當前訪問的節點管理的槽範圍內,則直接返回對應的資料
如果不在當前節點負責管理的槽範圍內,則會告訴客戶端去哪個節點獲取資料,由客戶端去正確的節點獲取資料

複製

保證高可用,每個主節點都有一個從節點,當主節點故障,Cluster會按照規則實現主備的高可用性

對於節點來說,有一個配置項:cluster-enabled,即是否以叢集模式啟動

客戶端路由

moved重定向

1.每個節點通過通訊都會共享Redis Cluster中槽和叢集中對應節點的關係
2.客戶端向Redis Cluster的任意節點發送命令,接收命令的節點會根據CRC16規則進行hash運算與16383取餘,計算自己的槽和對應節點
3.如果儲存資料的槽被分配給當前節點,則去槽中執行命令,並把命令執行結果返回給客戶端
4.如果儲存資料的槽不在當前節點的管理範圍內,則向客戶端返回moved重定向異常
5.客戶端接收到節點返回的結果,如果是moved異常,則從moved異常中獲取目標節點的資訊
6.客戶端向目標節點發送命令,獲取命令執行結果

需要注意的是:客戶端不會自動找到目標節點執行命令

槽命中:直接返回

[root@mysql ~]# redis-cli -p 9002 cluster keyslot hello
(integer) 866

槽不命中:moved異常

[root@mysql ~]# redis-cli -p 9002 cluster keyslot php
(integer) 9244
[root@mysql ~]# redis-cli -c -p 9002
127.0.0.1:9002> cluster keyslot hello
(integer) 866
127.0.0.1:9002> set hello world
-> Redirected to slot [866] located at 192.168.81.100:9003
OK
192.168.81.100:9003> cluster keyslot python
(integer) 7252
192.168.81.100:9003> set python best
-> Redirected to slot [7252] located at 192.168.81.101:9002
OK
192.168.81.101:9002> get python
"best"
192.168.81.101:9002> get hello
-> Redirected to slot [866] located at 192.168.81.100:9003
"world"
192.168.81.100:9003> exit
[root@mysql ~]# redis-cli -p 9002
127.0.0.1:9002> cluster keyslot python
(integer) 7252
127.0.0.1:9002> set python best
OK
127.0.0.1:9002> set hello world
(error) MOVED 866 192.168.81.100:9003
127.0.0.1:9002> exit

ask重定向

在對叢集進行擴容和縮容時,需要對槽及槽中資料進行遷移

當客戶端向某個節點發送命令,節點向客戶端返回moved異常,告訴客戶端資料對應的槽的節點資訊

如果此時正在進行叢集擴充套件或者縮空操作,當客戶端向正確的節點發送命令時,槽及槽中資料已經被遷移到別的節點了,就會返回ask,這就是ask重定向機制

步驟:

1.客戶端向目標節點發送命令,目標節點中的槽已經遷移支別的節點上了,此時目標節點會返回ask轉向給客戶端
2.客戶端向新的節點發送Asking命令給新的節點,然後再次向新節點發送命令
3.新節點執行命令,把命令執行結果返回給客戶端

moved異常與ask異常的相同點和不同點

兩者都是客戶端重定向
moved異常:槽已經確定遷移,即槽已經不在當前節點
ask異常:槽還在遷移中

smart智慧客戶端

使用智慧客戶端的首要目標:追求效能

從叢集中選一個可執行節點,使用Cluster slots初始化槽和節點對映

將Cluster slots的結果對映在本地,為每個節點建立JedisPool,相當於為每個redis節點都設定一個JedisPool,然後就可以進行資料讀寫操作

讀寫資料時的注意事項:

每個JedisPool中快取了slot和節點node的關係
key和slot的關係:對key進行CRC16規則進行hash後與16383取餘得到的結果就是槽
JedisCluster啟動時,已經知道key,slot和node之間的關係,可以找到目標節點
JedisCluster對目標節點發送命令,目標節點直接響應給JedisCluster
如果JedisCluster與目標節點連接出錯,則JedisCluster會知道連線的節點是一個錯誤的節點
此時JedisCluster會隨機節點發送命令,隨機節點返回moved異常給JedisCluster
JedisCluster會重新初始化slot與node節點的快取關係,然後向新的目標節點發送命令,目標命令執行命令並向JedisCluster響應
如果命令傳送次數超過5次,則丟擲異常"Too many cluster redirection!"

多節點命令實現

Redis Cluster不支援使用scan命令掃描所有節點,多節點命令就是在在所有節點上都執行一條命令,批量操作優化

1、序列mget:定義for迴圈,遍歷所有的key,分別去所有的Redis節點中獲取值並進行彙總,簡單,但是效率不高,需要n次網路時間

2、序列IO:

對序列mget進行優化,在客戶端本地做內聚,對每個key進行CRC16hash,然後與16383取餘,就可以知道哪個key對應的是哪個槽

本地已經快取了槽與節點的對應關係,然後對key按節點進行分組,成立子集,然後使用pipeline把命令傳送到對應的node,需要nodes次網路時間,大大減少了網路時間開銷

3、並行IO

並行IO是對序列IO的一個優化,把key分組之後,根據節點數量啟動對應的執行緒數,根據多執行緒模式並行向node節點請求資料,只需要1次網路時間

4、hash_tag

將key進行hash_tag的包裝,然後把tag用大括號括起來,保證所有的key只向一個node請求資料,這樣執行類似mget命令只需要去一個節點獲取資料即可,效率更高

3.7 故障發現

Redis Cluster通過ping/pong訊息實現故障發現:不需要sentinel

ping/pong不僅能傳遞節點與槽的對應訊息,也能傳遞其他狀態,比如:節點主從狀態,節點故障等

故障發現就是通過這種模式來實現,分為主觀下線和客觀下線

3.7.1 主觀下線

某個節點認為另一個節點不可用,'偏見',只代表一個節點對另一個節點的判斷,不代表所有節點的認知

主觀下線流程:

1.節點1定期傳送ping訊息給節點2
2.如果傳送成功,代表節點2正常執行,節點2會響應PONG訊息給節點1,節點1更新與節點2的最後通訊時間
3.如果傳送失敗,則節點1與節點2之間的通訊異常判斷連線,在下一個定時任務週期時,仍然會與節點2傳送ping訊息
4.如果節點1發現與節點2最後通訊時間超過node-timeout,則把節點2標識為pfail狀態
        

3.7.2 客觀下線

當半數以上持有槽的主節點都標記某節點主觀下線時,可以保證判斷的公平性

叢集模式下,只有主節點(master)才有讀寫許可權和叢集槽的維護許可權,從節點(slave)只有複製的許可權

客觀下線流程:

1.某個節點接收到其他節點發送的ping訊息,如果接收到的ping訊息中包含了其他pfail節點,這個節點會將主觀下線的訊息內容新增到自身的故障列表中,故障列表中包含了當前節點接收到的每一個節點對其他節點的狀態資訊
2.當前節點把主觀下線的訊息內容新增到自身的故障列表之後,會嘗試對故障節點進行客觀下線操作

故障列表的週期為:叢集的node-timeout * 2,保證以前的故障訊息不會對週期內的故障訊息造成影響,保證客觀下線的公平性和有效性

3.8 故障恢復

3.8.1 資格檢查

對從節點的資格進行檢查,只有難過檢查的從節點才可以開始進行故障恢復
每個從節點檢查與故障主節點的斷線時間
超過cluster-node-timeout * cluster-slave-validity-factor數字,則取消資格
cluster-node-timeout預設為15秒,cluster-slave-validity-factor預設值為10
如果這兩個引數都使用預設值,則每個節點都檢查與故障主節點的斷線時間,如果超過150秒,則這個節點就沒有成為替換主節點的可能性

3.9.2 準備選舉時間

使偏移量最大的從節點具備優先順序成為主節點的條件

3.8.3 選舉投票

對選舉出來的多個從節點進行投票,選出新的主節點

3.8.4 替換主節點

當前從節點取消複製變成離節點(slaveof no one)
執行cluster del slot撤銷故障主節點負責的槽,並執行cluster add slot把這些槽分配給自己
向叢集廣播自己的pong訊息,表明已經替換了故障從節點

3.8.5 故障轉移演練

對某一個主節點執行kill -9 {pid}來模擬宕機的情況

3.9 Redis Cluster的缺點

當節點數量很多時,效能不會很高
解決方式:使用智慧客戶端。智慧客戶端知道由哪個節點負責管理哪個槽,而且當節點與槽的對映關係發生改變時,客戶端也會知道這個改變,這是一種非常高效的方式

使用

4.搭建Redis Cluster

搭建Redis Cluster有兩種安裝方式

cluster-require-full-coverage預設為yes,即是否叢集中的所有節點都是線上狀態且16384個槽都處於服務狀態時,叢集才會提供服務

叢集中16384個槽全部處於服務狀態,保證叢集完整性

當某個節點故障或者正在故障轉移時獲取資料會提示:(error)CLUSTERDOWN The cluster is down

建議把cluster-require-full-coverage設定為no

5.2 頻寬消耗

Redis Cluster節點之間會定期交換Gossip訊息,以及做一些心跳檢測

官方建議Redis Cluster節點數量不要超過1000個,當叢集中節點數量過多時,會產生不容忽視的頻寬消耗

訊息傳送頻率:節點發現與其他節點最後通訊時間超過cluster-node-timeout /2時,會直接傳送PING訊息

訊息資料量:slots槽陣列(2kb空間)和整個叢集1/10的狀態資料(10個節點狀態資料約為1kb)

節點部署的機器規模:叢集分佈的機器越多且每臺機器劃分的節點數越均勻,則叢集內整體的可用頻寬越高

頻寬優化:

避免使用'大'叢集:避免多業務使用一個叢集,大業務可以多叢集
cluster-node-timeout:頻寬和故障轉移速度的均衡
儘量均勻分配到多機器上:保證高可用和頻寬

5.3 Pub/Sub廣播

在任意一個cluster節點執行publish,則釋出的訊息會在叢集中傳播,叢集中的其他節點都會訂閱到訊息,這樣節點的頻寬的開銷會很大

publish在叢集每個節點廣播,加重頻寬

解決辦法:需要使用Pub/Sub時,為了保證高可用,可以單獨開啟一套Redis Sentinel

5.4 叢集傾斜

對於分散式資料庫來說,存在傾斜問題是比較常見的

叢集傾斜也就是各個節點使用的記憶體不一致

5.4.1 資料傾斜原因

1.節點和槽分配不均,如果使用redis-trib.rb工具構建叢集,則出現這種情況的機會不多

redis-trib.rb info ip:port檢視節點,槽,鍵值分佈
redis-trib.rb rebalance ip:port進行均衡(謹慎使用)

2.不同槽對應鍵值數量差異比較大

CRC16演算法正常情況下比較均勻
可能存在hash_tag
cluster countkeysinslot {slot}獲取槽對應鍵值個數

3.包含bigkey:例如大字串,幾百萬的元素的hash,set等

在從節點:redis-cli --bigkeys
優化:優化資料結構

4.記憶體相關配置不一致

hash-max-ziplist-value:滿足一定條件情況下,hash可以使用ziplist
set-max-intset-entries:滿足一定條件情況下,set可以使用intset
在一個叢集內有若干個節點,當其中一些節點配置上面兩項優化,另外一部分節點沒有配置上面兩項優化
當叢集中儲存hash或者set時,就會造成節點資料不均勻
優化:定期檢查配置一致性

5.請求傾斜:熱點key

重要的key或者bigkey
Redis Cluster某個節點有一個非常重要的key,就會存在熱點問題

5.4.2 叢集傾斜優化:

避免bigkey
熱鍵不要用hash_tag
當一致性不高時,可以用本地快取+ MQ(訊息佇列)

5.5 叢集讀寫分離

只讀連線:叢集模式下,從節點不接受任何讀寫請求

當向從節點執行讀請求時,重定向到負責槽的主節點

readonly命令可以讀:連線級別命令,當連線斷開之後,需要再次執行readonly命令

讀寫分離:

同樣的問題:複製延遲,讀取過期資料,從節點故障
修改客戶端:cluster slaves {nodeId}

5.6 資料遷移

官方遷移工具:redis-trib.rb和import

只能從單機遷移到叢集

不支援線上遷移:source需要停寫

不支援斷點續傳

單執行緒遷移:影響深度

線上遷移:

唯品會:redis-migrate-tool
豌豆莢:redis-port

5.7 叢集VS單機

叢集的限制:

key批量操作支援有限:例如mget,mset必須在一個slot
key事務和Lua支援有限:操作的key必須在一個節點
key是資料分割槽的最小粒度:不支援bigkey分割槽
不支援多個數據庫:叢集模式下只有一個db0
複製只支援一層:不支援樹形複製結構
Redis Cluster滿足容量和效能的擴充套件性,很多業務'不需要'
大多數時客戶端效能會'降低'
命令無法跨節點使用:mget,keys,scan,flush,sinter等
Lua和事務無法跨節點使用
客戶端維護更復雜:SDK和應用本身消耗(例如更多的連線池)

很多場景Redis Sentinel已經夠用了

6.Redis Cluster總結:

1.Redis Cluster資料分割槽規則採用虛擬槽方式(16384個槽),每個節點負責一部分槽和相關資料,實現資料和請求的負載均衡
2.搭建Redis Cluster劃分四個步驟:準備節點,meet操作,分配槽,複製資料。
3.Redis官方推薦使用redis-trib.rb工具快速搭建Redis Cluster
4.叢集伸縮通過在節點之間移動槽和相關資料實現
    擴容時根據槽遷移計劃把槽從源節點遷移到新節點
    收縮時如果下線的節點有負責的槽需要遷移到其他節點,再通過cluster forget命令讓叢集內所有節點忘記被下線節點
5.使用smart客戶端操作叢集過到通訊效率最大化,客戶端內部負責計算維護鍵,槽以及節點的對映,用於快速定位到目標節點
6.叢集自動故障轉移過程分為故障發現和節點恢復。節點下線分為主觀下線和客觀下線,當超過半數節點認為故障節點為主觀下線時,標記這個節點為客觀下線狀態。從節點負責對客觀下線的主節點觸發故障恢復流程,保證叢集的可用性
7.開發運維常見問題包括:超大規模叢集帶席消耗,pub/sub廣播問題,叢集傾斜問題,單機和叢集對比等

Redis cluster搭建

https://www.jianshu.com/p/813a79ddf932

redis最開始使用主從模式做叢集,若master宕機需要手動配置slave轉為master;後來為了高可用提出來哨兵模式,該模式下有一個哨兵監視master和slave,若master宕機可自動將slave轉為master,但它也有一個問題,就是不能動態擴充;所以在3.x提出cluster叢集模式。

一、redis-cluster設計
Redis-Cluster採用無中心結構,每個節點儲存資料和整個叢集狀態,每個節點都和其他所有節點連線。

其結構特點:
1、所有的redis節點彼此互聯(PING-PONG機制),內部使用二進位制協議優化傳輸速度和頻寬。
2、節點的fail是通過叢集中超過半數的節點檢測失效時才生效。
3、客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連線叢集所有節點,連線叢集中任何一個可用節點即可。
4、redis-cluster把所有的物理節點對映到[0-16383]slot上(不一定是平均分配),cluster 負責維護node<->slot<->value。
5、Redis叢集預分好16384個桶,當需要在 Redis 叢集中放置一個 key-value 時,根據 CRC16(key) mod 16384的值,決定將一個key放到哪個桶中。

a.redis cluster節點分配
現在我們是三個主節點分別是:A, B, C 三個節點,它們可以是一臺機器上的三個埠,也可以是三臺不同的伺服器。那麼,採用雜湊槽 (hash slot)的方式來分配16384個slot 的話,它們三個節點分別承擔的slot 區間是:

  • 節點A覆蓋0-5460;

  • 節點B覆蓋5461-10922;

  • 節點C覆蓋10923-16383.

    獲取資料:
    如果存入一個值,按照redis cluster雜湊槽的演算法: CRC16('key')384 = 6782。 那麼就會把這個key 的儲存分配到 B 上了。同樣,當我連線(A,B,C)任何一個節點想獲取'key'這個key時,也會這樣的演算法,然後內部跳轉到B節點上獲取資料

    新增一個主節點:
    新增一個節點D,redis cluster的這種做法是從各個節點的前面各拿取一部分slot到D上,我會在接下來的實踐中實驗。大致就會變成這樣:

  • 節點A覆蓋1365-5460

  • 節點B覆蓋6827-10922

  • 節點C覆蓋12288-16383

  • 節點D覆蓋0-1364,5461-6826,10923-12287

同樣刪除一個節點也是類似,移動完成後就可以刪除這個節點了。

b.Redis Cluster主從模式
redis cluster 為了保證資料的高可用性,加入了主從模式,一個主節點對應一個或多個從節點,主節點提供資料存取,從節點則是從主節點拉取資料備份,當這個主節點掛掉後,就會有這個從節點選取一個來充當主節點,從而保證叢集不會掛掉

上面那個例子裡, 叢集有ABC三個主節點, 如果這3個節點都沒有加入從節點,如果B掛掉了,我們就無法訪問整個叢集了。A和C的slot也無法訪問。

所以我們在叢集建立的時候,一定要為每個主節點都添加了從節點, 比如像這樣, 叢集包含主節點A、B、C, 以及從節點A1、B1、C1, 那麼即使B掛掉系統也可以繼續正確工作。

B1節點替代了B節點,所以Redis叢集將會選擇B1節點作為新的主節點,叢集將會繼續正確地提供服務。 當B重新開啟後,它就會變成B1的從節點。

不過需要注意,如果節點B和B1同時掛了,Redis叢集就無法繼續正確地提供服務了。

二、redis叢集的搭建
叢集中至少應該有奇數個節點,所以至少有三個節點,每個節點至少有一個備份節點,所以下面使用6節點(主節點、備份節點由redis-cluster叢集確定)
下載redis
1、安裝redis節點指定埠
解壓redis壓縮包,編譯安裝

[root@localhost redis-3.2.0]# tar xzf redis-3.2.0.tar.gz
[root@localhost redis-3.2.0]# cd redis-3.2.0
[root@localhost redis-3.2.0]# make
[root@localhost redis01]# make install PREFIX=/usr/andy/redis-cluster

在redis-cluster下 修改bin資料夾為redis01,複製redis.conf配置檔案
建立目錄redis-cluster並在此目錄下再建立7000 7001 7002 7003 7004 7005共6個目錄,在7000中建立配置檔案redis.conf,內容如下:

        daemonize yes #後臺啟動
        port 7001 #修改埠號,從7001到7006
        cluster-enabled yes #開啟cluster,去掉註釋
        cluster-config-file nodes.conf #自動生成
        cluster-node-timeout 15000 #節點通訊時間
        appendonly yes #持久化方式

同時把redis.conf複製到其它目錄中

2、安裝redis-trib所需的 ruby指令碼
注意:centos7預設的ruby版本太低(2.0),要解除安裝重灌(最低2.2)

yum remove ruby
yum install ruby
yum install rubygems

複製redis解壓檔案src下的redis-trib.rb檔案到redis-cluster目錄並安裝gem

gem install redis-3.x.x.gem

若不想安裝src目錄下的gem,也可以直接gem install redis

注意,gem install可能會報錯
Unable to require openssl,install OpenSSL and rebuild ruby (preferred) or use ....
解決步驟:

  1. yum install openssl-devel -y
  2. 在ruby安裝包/root/ruby-x.x.x/ext/openssl,執行ruby ./extconf.rb
  3. 執行make,若出現make: *** No rule to make target /include/ruby.h', needed byossl.o'. Stop.;在Makefile頂部中的增加top_srcdir = ../..
  4. 執行make install

3、啟動所有的redis節點
可以寫一個命令指令碼start-all.sh

cd 7000
redis-server redis.conf
cd ..
cd 7001
redis-server redis.conf
cd ..
cd 7002
redis-server redis.conf
cd ..
cd 7003
redis-server redis.conf
cd ..
cd 7004
redis-server redis.conf
cd ..
cd 7005
redis-server redis.conf
cd ..

設定許可權啟動

[root@localhost redis-cluster]# chmod 777 start-all.sh 
[root@localhost redis-cluster]# ./start-all.sh 

檢視redis程序啟動狀態

[root@localhost redis-4.0.2]# ps -ef|grep cluster
root      54956      1  0 19:17 ?        00:00:00 redis-server *:7000 [cluster]
root      54961      1  0 19:17 ?        00:00:00 redis-server *:7001 [cluster]
root      54966      1  0 19:17 ?        00:00:00 redis-server *:7002 [cluster]
root      54971      1  0 19:17 ?        00:00:00 redis-server *:7003 [cluster]
root      54976      1  0 19:17 ?        00:00:00 redis-server *:7004 [cluster]
root      54981      1  0 19:17 ?        00:00:00 redis-server *:7005 [cluster]
root      55071  24089  0 19:24 pts/0    00:00:00 grep --color=auto cluster

可以看到redis的6個節點已經啟動成功
注意:這裡並沒有建立叢集

4、使用redis-trib.rb建立叢集
注意:redis-trib.rb在redis/src目錄下。

./redis-trib.rb create --replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7000

使用create命令 --replicas 1 引數表示為每個主節點建立一個從節點,其他引數是例項的地址集合。

[root@localhost redis]# ./src/redis-trib.rb create --replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7000
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7001
127.0.0.1:7002
127.0.0.1:7003
Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
Adding replica 127.0.0.1:7000 to 127.0.0.1:7003
M: f4ee0a501f9aaf11351787a46ffb4659d45b7bd7 127.0.0.1:7001
   slots:0-5460 (5461 slots) master
M: 671a0524a616da8b2f50f3d11a74aaf563578e41 127.0.0.1:7002
   slots:5461-10922 (5462 slots) master
M: 18948dab5b07e3726afd1b6a42d5bf6e2f411ba1 127.0.0.1:7003
   slots:10923-16383 (5461 slots) master
S: 34e322ca50a2842e9f3664442cb11c897defba06 127.0.0.1:7004
   replicates f4ee0a501f9aaf11351787a46ffb4659d45b7bd7
S: 62a00566233fbff4467c4031345b1db13cf12b46 127.0.0.1:7005
   replicates 671a0524a616da8b2f50f3d11a74aaf563578e41
S: 2cb649ad3584370c960e2036fb01db834a546114 127.0.0.1:7000
   replicates 18948dab5b07e3726afd1b6a42d5bf6e2f411ba1
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join...
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: f4ee0a501f9aaf11351787a46ffb4659d45b7bd7 127.0.0.1:7001
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: 671a0524a616da8b2f50f3d11a74aaf563578e41 127.0.0.1:7002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: 2cb649ad3584370c960e2036fb01db834a546114 127.0.0.1:7000
   slots: (0 slots) slave
   replicates 18948dab5b07e3726afd1b6a42d5bf6e2f411ba1
S: 34e322ca50a2842e9f3664442cb11c897defba06 127.0.0.1:7004
   slots: (0 slots) slave
   replicates f4ee0a501f9aaf11351787a46ffb4659d45b7bd7
M: 18948dab5b07e3726afd1b6a42d5bf6e2f411ba1 127.0.0.1:7003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 62a00566233fbff4467c4031345b1db13cf12b46 127.0.0.1:7005
   slots: (0 slots) slave
   replicates 671a0524a616da8b2f50f3d11a74aaf563578e41
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

上面顯示建立成功,有3個主節點,3個從節點,每個節點都是成功連線狀態。

三、redis叢集的測試
測試存取值,客戶端連線叢集redis-cli需要帶上 -c ,redis-cli -c -p 埠號

[root@localhost redis]# ./redis-cli -c -p 7001
127.0.0.1:7001> set name andy
-> Redirected to slot [5798] located at 127.0.0.1:7002
OK
127.0.0.1:7002> get name
"andy"
127.0.0.1:7002> 

根據redis-cluster的key值分配,name應該分配到節點7002[5461-10922]上,上面顯示redis cluster自動從7001跳轉到了7002節點。

測試一下7000從節點獲取name值

[root@localhost redis]# ./redis-cli -c -p 7000
127.0.0.1:7000> get name
-> Redirected to slot [5798] located at 127.0.0.1:7002
"andy"
127.0.0.1:7002> 

四、叢集節點選舉
現在模擬將7002節點掛掉,按照redis-cluster原理會選舉會將 7002的從節點7005選舉為主節點。

[root@localhost redis-cluster]# ps -ef | grep redis
root       7966      1  0 12:50 ?        00:00:29 ./redis-server 127.0.0.1:7000 [cluster]
root       7950      1  0 12:50 ?        00:00:28 ./redis-server 127.0.0.1:7001 [cluster]
root       7952      1  0 12:50 ?        00:00:29 ./redis-server 127.0.0.1:7002 [cluster]
root       7956      1  0 12:50 ?        00:00:29 ./redis-server 127.0.0.1:7003 [cluster]
root       7960      1  0 12:50 ?        00:00:29 ./redis-server 127.0.0.1:7004 [cluster]
root       7964      1  0 12:50 ?        00:00:29 ./redis-server 127.0.0.1:7005 [cluster]
root      11346  10581  0 14:57 pts/2    00:00:00 grep --color=auto redis
[root@localhost redis-cluster]# kill 7952

在檢視叢集中的7002節點

[root@localhost src]# ./redis-trib.rb check 127.0.0.1:7002
>>> Performing Cluster Check (using node 127.0.0.1:7002)
S: 671a0524a616da8b2f50f3d11a74aaf563578e41 127.0.0.1:7002
   slots: (0 slots) slave
   replicates 62a00566233fbff4467c4031345b1db13cf12b46
M: 18948dab5b07e3726afd1b6a42d5bf6e2f411ba1 127.0.0.1:7003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
M: 62a00566233fbff4467c4031345b1db13cf12b46 127.0.0.1:7005
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: f4ee0a501f9aaf11351787a46ffb4659d45b7bd7 127.0.0.1:7001
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: 34e322ca50a2842e9f3664442cb11c897defba06 127.0.0.1:7004
   slots: (0 slots) slave
   replicates f4ee0a501f9aaf11351787a46ffb4659d45b7bd7
S: 2cb649ad3584370c960e2036fb01db834a546114 127.0.0.1:7000
   slots: (0 slots) slave
   replicates 18948dab5b07e3726afd1b6a42d5bf6e2f411ba1
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

可以看到叢集連線不了7002節點,而7005有原來的S轉換為M節點,代替了原來的7002節點。我們可以獲取name值:

[root@localhost redis]# ./redis-cli -c -p 7001
127.0.0.1:7001> get name
-> Redirected to slot [5798] located at 127.0.0.1:7005
"andy"
127.0.0.1:7005> 
127.0.0.1:7005> 

從7001節點連入,自動跳轉到7005節點,並且獲取name值。

現在我們將7002節點恢復,看是否會自動加入叢集中以及充當的M還是S節點。

[root@localhost redis-cluster]# cd 7002
[root@localhost 7002]# ./redis-server redis.conf 
[root@localhost 7002]# 

再check一下7002節點,可以看到7002節點變成了7005的從節點。