Redis cluster集羣模式的原理

 

redis clusterjava

  redis cluster是Redis的分佈式解決方案,在3.0版本推出後有效地解決了redis分佈式方面的需求node

  自動將數據進行分片,每一個master上放一部分數據面試

  提供內置的高可用支持,部分master不可用時,仍是能夠繼續工做的redis

 

  支撐N個redis master node,每一個master node均可以掛載多個slave node算法

  高可用,由於每一個master都有salve節點,那麼若是mater掛掉,redis cluster這套機制,就會自動將某個slave切換成master數據庫

 

redis cluster vs. replication + sentinalapi

  若是你的數據量不多,主要是承載高併發高性能的場景,好比你的緩存通常就幾個G,單機足夠了緩存

  replication,一個mater,多個slave,要幾個slave跟你的要求的讀吞吐量有關係,而後本身搭建一個sentinal集羣,去保證redis主從架構的高可用性,就能夠了網絡

  redis cluster,主要是針對海量數據+高併發+高可用的場景,海量數據,若是你的數據量很大,那麼建議就用redis cluster架構

 

數據分佈算法

hash算法

  好比你有 N 個 redis實例,那麼如何將一個key映射到redis上呢,你極可能會採用相似下面的通用方法計算 key的 hash 值,而後均勻的映射到到 N 個 redis上:

  hash(key)%N

  若是增長一個redis,映射公式變成了 hash(key)%(N+1)

  若是一個redis宕機了,映射公式變成了 hash(key)%(N-1)

  在這兩種狀況下,幾乎全部的緩存都失效了。會致使數據庫訪問的壓力陡增,嚴重狀況,還可能致使數據庫宕機。

 

一致性hash算法

  一個master宕機不會致使大部分緩存失效,可能存在緩存熱點問題

 

用虛擬節點改進

 

 

 

redis cluster的hash slot算法

  redis cluster有固定的16384個hash slot,對每一個key計算CRC16值,而後對16384取模,能夠獲取key對應的hash slot

  redis cluster中每一個master都會持有部分slot,好比有3個master,那麼可能每一個master持有5000多個hash slot

  hash slot讓node的增長和移除很簡單,增長一個master,就將其餘master的hash slot移動部分過去,減小一個master,就將它的hash slot移動到其餘master上去

  移動hash slot的成本是很是低的

  客戶端的api,能夠對指定的數據,讓他們走同一個hash slot,經過hash tag來實現

 

  127.0.0.1:7000>CLUSTER ADDSLOTS 0 1 2 3 4 ... 5000  能夠將槽0-5000指派給節點7000負責。

  每一個節點都會記錄哪些槽指派給了本身,哪些槽指派給了其餘節點。

  客戶端向節點發送鍵命令,節點要計算這個鍵屬於哪一個槽。

  若是是本身負責這個槽,那麼直接執行命令,若是不是,向客戶端返回一個MOVED錯誤,指引客戶端轉向正確的節點。

 

 

redis cluster  多master的寫入

  在redis cluster寫入數據的時候,實際上是你能夠將請求發送到任意一個master上去執行

  可是,每一個master都會計算這個key對應的CRC16值,而後對16384個hashslot取模,找到key對應的hashslot,找到hashslot對應的master

  若是對應的master就在本身本地的話,set mykey1 v1,mykey1這個key對應的hashslot就在本身本地,那麼本身就處理掉了

  可是若是計算出來的hashslot在其餘master上,那麼就會給客戶端返回一個moved error,告訴你,你獲得哪一個master上去執行這條寫入的命令

 

  什麼叫作多master的寫入,就是每條數據只能存在於一個master上,不一樣的master負責存儲不一樣的數據,分佈式的數據存儲

  100w條數據,5個master,每一個master就負責存儲20w條數據,分佈式數據存儲

 

  默認狀況下,redis cluster的核心的理念,主要是用slave作高可用的,每一個master掛一兩個slave,主要是作數據的熱備,還有master故障時的主備切換,實現高可用的

  redis cluster默認是不支持slave節點讀或者寫的,跟咱們手動基於replication搭建的主從架構不同的

 

  jedis客戶端,對redis cluster的讀寫分離支持不太好的

  默認的話就是讀和寫都到master上去執行的

  若是你要讓最流行的jedis作redis cluster的讀寫分離的訪問,那可能還得本身修改一點jedis的源碼,成本比較高

 

  讀寫分離,是爲了什麼,主要是由於要創建一主多從的架構,才能橫向任意擴展slave node去支撐更大的讀吞吐量

  redis cluster的架構下,實際上自己master就是能夠任意擴展的,你若是要支撐更大的讀吞吐量,或者寫吞吐量,或者數據量,均可以直接對master進行橫向擴展就能夠了

 

 

 

 

 


節點間的內部通訊機制

一、基礎通訊原理

(1)redis cluster節點間採起gossip協議進行通訊

  跟集中式不一樣,不是將集羣元數據(節點信息,故障,等等)集中存儲在某個節點上,而是互相之間不斷通訊,保持整個集羣全部節點的數據是完整的

  集中式:好處在於,元數據的更新和讀取,時效性很是好,一旦元數據出現了變動,當即就更新到集中式的存儲中,其餘節點讀取的時候當即就能夠感知到; 很差在於,全部的元數據的跟新壓力所有集中在一個地方,可能會致使元數據的存儲有壓力

  gossip:好處在於,元數據的更新比較分散,不是集中在一個地方,更新請求會陸陸續續,打到全部節點上去更新,有必定的延時,下降了壓力; 缺點,元數據更新有延時,可能致使集羣的一些操做會有一些滯後

 

(2)10000端口

  每一個節點都有一個專門用於節點間通訊的端口,就是本身提供服務的端口號+10000,好比7001,那麼用於節點間通訊的就是17001端口

  每隔節點每隔一段時間都會往另外幾個節點發送ping消息,同時其餘幾點接收到ping以後返回pong

 

(3)交換的信息

  故障信息,節點的增長和移除,hash slot信息,等等

 

二、gossip協議

  gossip協議包含多種消息,包括ping,pong,meet,fail,等等

  meet: 某個節點發送meet給新加入的節點,讓新節點加入集羣中,而後新節點就會開始與其餘節點進行通訊

  redis-trib.rb add-node

  其實內部就是發送了一個gossip meet消息,給新加入的節點,通知那個節點去加入咱們的集羣

  ping: 每一個節點都會頻繁給其餘節點發送ping,其中包含本身的狀態還有本身維護的集羣元數據,互相經過ping交換元數據

  每一個節點每秒都會頻繁發送ping給其餘的集羣,ping,頻繁的互相之間交換數據,互相進行元數據的更新

  pong: 返回ping和meet,包含本身的狀態和其餘信息,也能夠用於信息廣播和更新

  fail: 某個節點判斷另外一個節點fail以後,就發送fail給其餘節點,通知其餘節點,指定的節點宕機了

 

三、ping消息深刻

  ping很頻繁,並且要攜帶一些元數據,因此可能會加劇網絡負擔

  每一個節點每秒會執行10次ping,每次會選擇5個最久沒有通訊的其餘節點

  固然若是發現某個節點通訊延時達到了cluster_node_timeout / 2,那麼當即發送ping,避免數據交換延時過長,落後的時間太長了

  好比說,兩個節點之間都10分鐘沒有交換數據了,那麼整個集羣處於嚴重的元數據不一致的狀況,就會有問題

  因此cluster_node_timeout能夠調節,若是調節比較大,那麼會下降發送的頻率

  每次ping,一個是帶上本身節點的信息,還有就是帶上1/10其餘節點的信息,發送出去,進行數據交換

  至少包含3個其餘節點的信息,最多包含總節點-2個其餘節點的信息

 

 

基於重定向的客戶端

(1)請求重定向

  客戶端可能會挑選任意一個redis實例去發送命令,每一個redis實例接收到命令,都會計算key對應的hash slot

  若是在本地就在本地處理,不然返回moved給客戶端,讓客戶端進行重定向

  cluster keyslot mykey,能夠查看一個key對應的hash slot是什麼

  用redis-cli的時候,能夠加入-c參數,支持自動的請求重定向,redis-cli接收到moved以後,會自動重定向到對應的節點執行命令

 

(2)計算hash slot

  計算hash slot的算法,就是根據key計算CRC16值,而後對16384取模,拿到對應的hash slot

  用hash tag能夠手動指定key對應的slot,同一個hash tag下的key,都會在一個hash slot中,好比set mykey1:{100}和set mykey2:{100}

 

(3)hash slot查找

  節點間經過gossip協議進行數據交換,就知道每一個hash slot在哪一個節點上

 

smart jedis

(1)什麼是smart jedis

  基於重定向的客戶端,很消耗網絡IO,由於大部分狀況下,可能都會出現一次請求重定向,才能找到正確的節點

  因此大部分的客戶端,好比java redis客戶端,就是jedis,都是smart的

  本地維護一份hashslot -> node的映射表,緩存,大部分狀況下,直接走本地緩存就能夠找到hashslot -> node,不須要經過節點進行moved重定向

 

(2)JedisCluster的工做原理

  在JedisCluster初始化的時候,就會隨機選擇一個node,初始化hashslot -> node映射表,同時爲每一個節點建立一個JedisPool鏈接池

  每次基於JedisCluster執行操做,首先JedisCluster都會在本地計算key的hashslot,而後在本地映射表找到對應的節點

  若是那個node正好仍是持有那個hashslot,那麼就ok; 若是說進行了reshard這樣的操做,可能hashslot已經不在那個node上了,就會返回moved

  若是JedisCluter API發現對應的節點返回moved,那麼利用該節點的元數據,更新本地的hashslot -> node映射表緩存

  重複上面幾個步驟,直到找到對應的節點,若是重試超過5次,那麼就報錯,JedisClusterMaxRedirectionException

  jedis老版本,可能會出如今集羣某個節點故障還沒完成自動切換恢復時,頻繁更新hash slot,頻繁ping節點檢查活躍,致使大量網絡IO開銷

  jedis最新版本,對於這些過分的hash slot更新和ping,都進行了優化,避免了相似問題

 

(3)hashslot遷移和ask重定向

  若是hash slot正在遷移,那麼會返回ask重定向給jedis

  jedis接收到ask重定向以後,會從新定位到目標節點去執行,可是由於ask發生在hash slot遷移過程當中,因此JedisCluster API收到ask是不會更新hashslot本地緩存

  已經能夠肯定說,hashslot已經遷移完了,moved是會更新本地hashslot->node映射表緩存的

 

高可用性與主備切換原理

redis cluster的高可用的原理,幾乎跟哨兵是相似的

一、判斷節點宕機

  若是一個節點認爲另一個節點宕機,那麼就是pfail,主觀宕機

  若是多個節點都認爲另一個節點宕機了,那麼就是fail,客觀宕機,跟哨兵的原理幾乎同樣,sdown,odown

  在cluster-node-timeout內,某個節點一直沒有返回pong,那麼就被認爲pfail

  若是一個節點認爲某個節點pfail了,那麼會在gossip ping消息中,ping給其餘節點,若是超過半數的節點都認爲pfail了,那麼就會變成fail

 

二、從節點過濾

  對宕機的master node,從其全部的slave node中,選擇一個切換成master node

  檢查每一個slave node與master node斷開鏈接的時間,若是超過了cluster-node-timeout * cluster-slave-validity-factor,那麼就沒有資格切換成master

  這個也是跟哨兵是同樣的,從節點超時過濾的步驟

 

三、從節點選舉

  哨兵:對全部從節點進行排序,slave priority,offset,run id

  每一個從節點,都根據本身對master複製數據的offset,來設置一個選舉時間,offset越大(複製數據越多)的從節點,選舉時間越靠前,優先進行選舉

  全部的master node開始slave選舉投票,給要進行選舉的slave進行投票,若是大部分master node(N/2 + 1)都投票給了某個從節點,那麼選舉經過,那個從節點能夠切換成master

  從節點執行主備切換,從節點切換爲主節點

 

四、與哨兵比較

  整個流程跟哨兵相比,很是相似,因此說,redis cluster功能強大,直接集成了replication和sentinal的功能

 

 

轉自:中華石杉Java工程師面試突擊

相關文章
相關標籤/搜索