Redis系列九:redis集群高可用


Redis集群的概念:

  RedisClusterredis的分布式解決方案,在3.0版本后推出的方案,有效地解決了Redis分布式的需求,當一個服務掛了可以快速的切換到另外一個服務,當遇到單機內存、並發等瓶頸時,可使用此方案來解決這些問題

一、分布式數據庫概念

1. 分布式數據庫把整個數據按分區規則映射到多個節點,即把數據划分到多個節點上,每個節點負責整體數據的一個子集。比如我們庫有900條用戶數據,有3redis節點,將900條分成3份,分別存入到3redis節點

2. 分區規則:

   常見的分區規則哈希分區和順序分區,redis集群使用了哈希分區,順序分區暫用不到,不做具體說明;

   rediscluster采用了哈希分區的“虛擬槽分區”方式(哈希分區分節點取余、一致性哈希分區和虛擬槽分區),其它兩種也不做介紹,有興趣可以百度了解一下

3. 虛擬槽分區(槽:slot)

   RedisCluster采用此分區,所有的鍵根據哈希函數(CRC16[key]&16383)映射到016383槽內,共16384個槽位,每個節點維護部分槽及槽所映射的鍵值數據

   哈希函數: Hash()=CRC16[key]&16383 按位與

   槽與節點的關系如下

redis用虛擬槽分區原因:解耦數據與節點關系,節點自身維護槽映射關系,分布式存儲

4. redisCluster的缺陷:

a,鍵的批量操作支持有限,比如mset, mget,如果多個鍵映射在不同的槽,就不支持了

b,鍵事務支持有限,當多個key分布在不同節點時無法使用事務,同一節點是支持事務

c,鍵是數據分區的最小粒度,不能將一個很大的鍵值對映射到不同的節點

d不支持多數據庫,只有0select 0

e,復制結構只支持單層結構,不支持樹型結構。  

二、集群環境搭建-手動篇

部署結構圖:6389為6379的從節點,6390為6380的從節點,6391為6381的從節點

 

 

1.在/usr/local/bin/目錄下新建一個文件夾clusterconf,用來存放集群的配置文件

2. 分別修改637963807381638963906391配置文件

以6379的配置為例:

   port 6379                      //節點端口

   cluster-enabled yes              //開啟集群模式

   cluster-node-timeout 15000       //節點超時時間(接收pong消息回復的時間)

   cluster-config-file  /usr/localbin/cluster/data/nodes-6379.conf 集群內部配置文件

  其它節點的配置和這個一致,改端口即可

3. 配置完后,啟動6redis服務

./redis-server clusterconf/redis6379.conf &

./redis-server clusterconf/redis6380.conf &

./redis-server clusterconf/redis6381.conf &

./redis-server clusterconf/redis6389.conf &

./redis-server clusterconf/redis6390.conf &

./redis-server clusterconf/redis6391.conf &

4. 各節點啟動后,使用cluster meet ip port與各節點握手,是集群通信的第一步(關鍵步驟1:集群搭建-與各節點握手

 

5. 握手成功后,使用cluster nodes可以看到各節點都可以互相查詢到

 

6. 節點握手成功后,此時集群處理下線狀態,所有讀寫都被禁止

7. 使用cluster info命令獲取集群當前狀態

 

8. redis集群有16384個哈希槽,要把所有數據映射到16384槽,需要批量設置槽(關鍵步驟2:集群搭建-分配槽

redis-cli -h 192.168.152.128 -p 6379 cluster addslots {0...5461}

redis-cli -h 192.168.152.128 -p 6380 cluster addslots {5641...10922}

redis-cli -h 192.168.152.128 -p 6381 cluster addslots {10923...16383}

9. 分配完槽后,可查看集群狀態cluster info

11. 然后再查看cluster nodes,查看每個節點的ID

12. 6389639063916379,6380,6381做主從映射(關鍵步驟3:集群搭建-集群映射),到此redis集群手動搭建完成

 192.168.152.128:6389> cluster replicate 9b7b0c22f95eb01fb9935ad4b04d396c7f99e881

192.168.152.128:6390> cluster replicate 5351c088472467ae485ed519cea271efda646bfa

 92.168.152.128:6391> cluster replicate e718f126278072e1e180c3e518d73e0bc877b3dc

三、集群環境搭建-自動

使用ruby來自動分配槽與主從分配,見redis安裝文檔,建議用此方式完成

1.首先下載ruby-2.3.1.tar.gz   和  redis-3.3.0.gem,然后把這兩個工具通過winscp傳入linux虛擬機

2. /usr/local新建目錄:ruby

開始安裝第一步中下載的兩個軟件

tar -zxvf ruby-2.3.1.tar.gz 

a) cd /software/rubysoft/ruby-2.3.1

b) ./configure -prefix=/usr/local/ruby

c)  make && make install   //過程會有點慢,大概510分鍾

d) 然后gem install -l redis-3.3.0.gem  //沒有gem需要安裝yum install gem或者yum install rubygems

e) 准備好6個節點,(注意不要設置requirepass,/usr/local/bin/clusterconf/data之前手動配置config-file文件刪除;依次啟動6個節點:

./redis-server clusterconf/redis6379.conf

....

如果之前redis有數據存在,flushall清空;(:不需要cluster meet ..)

f) 進入cd /usr/local/bin,  執行以下:1代表從節點的個數(最關鍵的一步:通過這個命令可以自動完成之前手動配置集群的握手、分配槽位、主從映射

./redis-trib.rb create --replicas 1 192.168.152.128:6379 192.168.152.128:6380 192.168.152.128:6381 192.168.152.128:6389 192.168.152.128:6390 192.168.152.128:6391

主從分配,63796389的主節點,6380是6390的主節點,6381是6391的主節點,

貌似只有主節點可讀寫,從節點只能讀

主節點死后,從節點變成主節點

3.集群搭建好以后開始測試

a) 連入redis集群並設置值./redis-cli -h 192.168.152.128 -p 6379 -c

可以看到設置name以后,重定向到了6380的這個redis,這時因為鍵name經過CRC16[k]&16284虛擬槽分區算法以后落到了6380這個節點,所以數據就存到了6380這個redis節點

切回6379獲取name的值也會通過同樣的算法重定向到6380

4.集群健康檢查

./redis-trib.rb check 192.168.152.128:6379 (注:redis先去注釋掉requirepass,不然連不上)

正常的

 

不正常的(來源於網絡資源)

如此出現了這個問題,63795798槽位號被打開了

解決如下:

637963806381的有部分槽位被打開了,分別進入這幾個節點,執行

6380:>cluster setslot 1180 stable

cluster setslot 2998 stable

cluster setslot 11212 stable

其它也一樣,分別執行修復完后:

 

當停掉6379后,過會6389變成主節點

集群正常啟動后,在每個redis.conf里加上

   masterauth “12345678”

   requiredpass “12345678”

  當主節點下線時,從節點會變成主節點,用戶和密碼是很有必要的,設置成一致

5.集群的多主多從

配置如下:

./redis-trib.rb create --replicas 2

192.168.1.111:6379 192.168.1.111:6380 192.168.1.111:6381

192.168.1.111:6479 192.168.1.111:6480 192.168.1.111:6481

192.168.1.111:6579 192.168.1.111:6580 192.168.1.111:6581 

6.集群節點之間的通信

 1. 節點之間采用Gossip協議進行通信,Gossip協議就是指節點彼此之間不斷通信交換信息

 

 

當主從角色變化或新增節點,彼此通過ping/pong進行通信知道全部節點的最新狀態並達到集群同步

 2. Gossip協議

Gossip協議的主要職責就是信息交換,信息交換的載體就是節點之間彼此發送的Gossip消息,常用的Gossip消息有ping消息、pong消息、meet消息、fail消息

 

meet消息:用於通知新節點加入,消息發送者通知接收者加入到當前集群,meet消息通信完后,接收節點會加入到集群中,並進行周期性ping pong交換

ping消息:集群內交換最頻繁的消息,集群內每個節點每秒向其它節點發ping消息,用於檢測節點是在在線和狀態信息,ping消息發送封裝自身節點和其他節點的狀態數據;

pong消息,當接收到ping meet消息時,作為響應消息返回給發送方,用來確認正常通信,pong消息也封閉了自身狀態數據;

fail消息:當節點判定集群內的另一節點下線時,會向集群內廣播一個fail消息,

3. 消息解析流程

所有消息格式為:消息頭、消息體,消息頭包含發送節點自身狀態數據(比如節點ID、槽映射、節點角色、是否下線等),接收節點根據消息頭可以獲取到發送節點的相關數據。

消息解析流程:

 

 

 

4. 選擇節點並發送ping消息:

  Gossip協議信息的交換機制具有天然的分布式特性,但ping pong發送的頻率很高,可以實時得到其它節點的狀態數據,但頻率高會加重帶寬和計算能力,因此每次都會有目的性地選擇一些節點; 但是節點選擇過少又會影響故障判斷的速度,redis集群的Gossip協議兼顧了這兩者的優缺點,看下圖:

 

不難看出:節點選擇的流程可以看出消息交換成本主要體現在發送消息的節點數量和每個消息攜帶的數據量

流程說明:

A,選擇發送消息的節點數量:集群內每個節點維護定時任務默認為每秒執行10次,每秒會隨機選取5個節點,找出最久沒有通信的節點發送ping消息,用來保證信息交換的隨機性,每100毫秒都會掃描本地節點列表,如果發現節點最近一次接受pong消息的時間大於cluster-node-timeout/2 則立刻發送ping消息,這樣做目的是防止該節點信息太長時間沒更新,當我們寬帶資源緊張時,在可redis.confcluster-node-timeout 15000  改成30秒,但不能過度加大

B,消息數據:節點自身信息和其他節點信息

四、redis集群擴容

這也是分布式存儲最常見的需求,當我們存儲不夠用時,要考慮擴容

擴容步驟如下:

A. 准備好新節點

B. 加入集群,遷移槽和數據

1) 同目錄下新增redis6382.confredis6392.conf兩個redis節點

啟動兩個新redis節點

./redis-server clusterconf/redis6382.conf &  (新主節點)

./redis-server clusterconf/redis6392.conf &   (新從節點)

2) 新增主節點

 ./redis-trib.rb add-node 192.168.152.128:6382 192.168.152.128:6379  

6379是原存在的主節點,6382是新的主節點

 

3),添加從節點

redis-trib.rb add-node --slave --master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2 192.168.152.128:6392 192.168.152.128:6379  

    --slave,表示添加的是從節點

    --master-id 03ccad2ba5dd1e062464bc7590400441fafb63f2表示主節點6382master_id

    192.168.152.128:6392,新從節點

    192.168.152.128:6379集群原存在的舊節點

 

4) redis-trib.rb reshard 192.168.152.128:6382   //為新主節點重新分配solt

How many slots do you want to move (from 1 to 16384)? 1000 //設置slot1000

What is the receiving node ID? 464bc7590400441fafb63f2 //新節點node id

Source node #1:all //表示全部節點重新洗牌

新增完畢!

五、集群減縮節點

集群同時也支持節點下線掉,下線的流程如下:

流程說明:

A,確定下線節點是否存在槽slot,如果有,需要先把槽遷移到其他節點,保證整個集群槽節點映射的完整性;

B,當下線的節點沒有槽或本身是從節點時,就可以通知集群內其它節點(或者叫忘記節點),當下線節點被忘記后正常關閉。

刪除節點也分兩種:

一種是主節點6382,一種是從節點6392

在從節點6392中,沒有分配哈希槽,執行

./redis-trib.rb del-node 192.168.1.111:6392 7668541151b4c37d2d9 有兩個參數ipport  和節點的id。 從節點6392從集群中刪除了。

主節點6382刪除步驟:

1./redis-trib.rb reshard 192.168.1.111:6382

  問我們有多少個哈希槽要移走,因為我們這個節點上剛分配了1000 個所以我們這里輸入1000

2,最后

./redis-trib.rb del-node 192.168.1.111:6382 3e50c6398c75e0088a41f908071c2c2eda1dc900

此時節點下線完成……

 六、故障轉移

redis集群實現了高可用,當集群內少量節點出現故障時,通過故障轉移可以保證集群正常對外提供服務。

當集群里某個節點出現了問題,redis集群內的節點通過ping pong消息發現節點是否健康,是否有故障,其實主要環節也包括了 主觀下線和客觀下線;

主觀下線:指某個節點認為另一個節點不可用,即下線狀態,當然這個狀態不是最終的故障判定,只能代表這個節點自身的意見,也有可能存在誤判;

 

 

下線流程:

A,節點a發送ping消息給節點b ,如果通信正常將接收到pong消息,節點a更新最近一次與節點b的通信時間;

B,如果節點a與節點b通信出現問題則斷開連接,下次會進行重連,如果一直通信失敗,則它們的最后通信時間將無法更新;

節點a內的定時任務檢測到與節點b最后通信時間超過cluster_note-timeout時,更新本地對節點b的狀態為主觀下線(pfail

客觀下線:指真正的下線,集群內多個節點都認為該節點不可用,達成共識,將它下線,如果下線的節點為主節點,還要對它進行故障轉移

假如節點a標記節點b為主觀下線,一段時間后節點a通過消息把節點b的狀態發到其它節點,當節點c接受到消息並解析出消息體時,會發現節點bpfail狀態時,會觸發客觀下線流程;

當下線為主節點時,此時redis集群為統計持有槽的主節點投票數是否達到一半,當下線報告統計數大於一半時,被標記為客觀下線狀態。

故障恢復:

故障主節點下線后,如果下線節點的是主節點,則需要在它的從節點中選一個替換它,保證集群的高可用;轉移過程如下:

 

1,資格檢查:檢查該從節點是否有資格替換故障主節點,如果此從節點與主節點斷開過通信,那么當前從節點不具體故障轉移;

2,准備選舉時間:當從節點符合故障轉移資格后,更新觸發故障選舉時間,只有到達該時間后才能執行后續流程;

3,發起選舉:當到達故障選舉時間時,進行選舉;

4,選舉投票:只有持有槽的主節點才有票,會處理故障選舉消息,投票過程其實是一個領導者選舉(選舉從節點為領導者)的過程,每個主節點只能投一張票給從節點,當從節點收集到足夠的選票(大於N/2+1)后,觸發替換主節點操作,撤銷原故障主節點的槽,委派給自己,並廣播自己的委派消息,通知集群內所有節點。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM