redis 集羣模式的工做原理能說一下麼?在集羣模式下,redis 的 key 是如何尋址的?分佈式尋址都有哪些算法?瞭解一致性 hash 算法嗎?node
在前幾年,redis 若是要搞幾個節點,每一個節點存儲一部分的數據,得藉助一些中間件來實現,好比說有 codis
,或者 twemproxy
,都有。有一些 redis 中間件,你讀寫 redis 中間件,redis 中間件負責將你的數據分佈式存儲在多臺機器上的 redis 實例中。面試
這兩年,redis 不斷在發展,redis 也不斷有新的版本,如今的 redis 集羣模式,能夠作到在多臺機器上,部署多個 redis 實例,每一個實例存儲一部分的數據,同時每一個 redis 主實例能夠掛 redis 從實例,自動確保說,若是 redis 主實例掛了,會自動切換到 redis 從實例上來。redis
如今 redis 的新版本,你們都是用 redis cluster 的,也就是 redis 原生支持的 redis 集羣模式,那麼面試官確定會就 redis cluster 對你來個幾連炮。要是你沒用過 redis cluster,正常,之前不少人用 codis 之類的客戶端來支持集羣,可是起碼你得研究一下 redis cluster 吧。算法
若是你的數據量不多,主要是承載高併發高性能的場景,好比你的緩存通常就幾個 G,單機就足夠了,可使用 replication,一個 master 多個 slaves,要幾個 slave 跟你要求的讀吞吐量有關,而後本身搭建一個 sentinel 集羣去保證 redis 主從架構的高可用性。數據庫
redis cluster,主要是針對海量數據+高併發+高可用的場景。redis cluster 支撐 N 個 redis master node,每一個 master node 均可以掛載多個 slave node。這樣整個 redis 就能夠橫向擴容了。若是你要支撐更大數據量的緩存,那就橫向擴容更多的 master 節點,每一個 master 節點就能存放更多的數據了。api
在 redis cluster 架構下,每一個 redis 要放開兩個端口號,好比一個是 6379,另一個就是 加1w 的端口號,好比 16379。緩存
16379 端口號是用來進行節點間通訊的,也就是 cluster bus 的東西,cluster bus 的通訊,用來進行故障檢測、配置更新、故障轉移受權。cluster bus 用了另一種二進制的協議,gossip
協議,用於節點間進行高效的數據交換,佔用更少的網絡帶寬和處理時間。bash
集羣元數據的維護有兩種方式:集中式、Gossip 協議。redis cluster 節點間採用 gossip 協議進行通訊。服務器
集中式是將集羣元數據(節點信息、故障等等)幾種存儲在某個節點上。集中式元數據集中存儲的一個典型表明,就是大數據領域的 storm
。它是分佈式的大數據實時計算引擎,是集中式的元數據存儲的結構,底層基於 zookeeper(分佈式協調的中間件)對全部元數據進行存儲維護。網絡
redis 維護集羣元數據採用另外一個方式, gossip
協議,全部節點都持有一份元數據,不一樣的節點若是出現了元數據的變動,就不斷將元數據發送給其它的節點,讓其它節點也進行元數據的變動。
集中式的好處在於,元數據的讀取和更新,時效性很是好,一旦元數據出現了變動,就當即更新到集中式的存儲中,其它節點讀取的時候就能夠感知到;很差在於,全部的元數據的更新壓力所有集中在一個地方,可能會致使元數據的存儲有壓力。
gossip 好處在於,元數據的更新比較分散,不是集中在一個地方,更新請求會陸陸續續打到全部節點上去更新,下降了壓力;很差在於,元數據的更新有延時,可能致使集羣中的一些操做會有一些滯後。
10000 端口:每一個節點都有一個專門用於節點間通訊的端口,就是本身提供服務的端口號+10000,好比 7001,那麼用於節點間通訊的就是 17001 端口。每一個節點每隔一段時間都會往另外幾個節點發送 ping
消息,同時其它幾個節點接收到 ping
以後返回 pong
。
交換的信息:信息包括故障信息,節點的增長和刪除,hash slot 信息等等。
gossip 協議包含多種消息,包含 ping
,pong
,meet
,fail
等等。
redis-trib.rb add-node
複製代碼
其實內部就是發送了一個 gossip meet 消息給新加入的節點,通知那個節點去加入咱們的集羣。
ping 時要攜帶一些元數據,若是很頻繁,可能會加劇網絡負擔。
每一個節點每秒會執行 10 次 ping,每次會選擇 5 個最久沒有通訊的其它節點。固然若是發現某個節點通訊延時達到了 cluster_node_timeout / 2
,那麼當即發送 ping,避免數據交換延時過長,落後的時間太長了。好比說,兩個節點之間都 10 分鐘沒有交換數據了,那麼整個集羣處於嚴重的元數據不一致的狀況,就會有問題。因此 cluster_node_timeout
能夠調節,若是調得比較大,那麼會下降 ping 的頻率。
每次 ping,會帶上本身節點的信息,還有就是帶上 1/10 其它節點的信息,發送出去,進行交換。至少包含 3
個其它節點的信息,最多包含 總節點數減 2
個其它節點的信息。
來了一個 key,首先計算 hash 值,而後對節點數取模。而後打在不一樣的 master 節點上。一旦某一個 master 節點宕機,全部請求過來,都會基於最新的剩餘 master 節點數去取模,嘗試去取數據。這會致使大部分的請求過來,所有沒法拿到有效的緩存,致使大量的流量涌入數據庫。
一致性 hash 算法將整個 hash 值空間組織成一個虛擬的圓環,整個空間按順時針方向組織,下一步將各個 master 節點(使用服務器的 ip 或主機名)進行 hash。這樣就能肯定每一個節點在其哈希環上的位置。
來了一個 key,首先計算 hash 值,並肯定此數據在環上的位置,今後位置沿環順時針「行走」,遇到的第一個 master 節點就是 key 所在位置。
在一致性哈希算法中,若是一個節點掛了,受影響的數據僅僅是此節點到環空間前一個節點(沿着逆時針方向行走遇到的第一個節點)之間的數據,其它不受影響。增長一個節點也同理。
燃鵝,一致性哈希算法在節點太少時,容易由於節點分佈不均勻而形成緩存熱點的問題。爲了解決這種熱點問題,一致性 hash 算法引入了虛擬節點機制,即對每個節點計算多個 hash,每一個計算結果位置都放置一個虛擬節點。這樣就實現了數據的均勻分佈,負載均衡。
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
來實現。
任何一臺機器宕機,另外兩個節點,不影響的。由於 key 找的是 hash slot,不是機器。
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
。
每一個從節點,都根據本身對 master 複製數據的 offset,來設置一個選舉時間,offset 越大(複製數據越多)的從節點,選舉時間越靠前,優先進行選舉。
全部的 master node 開始 slave 選舉投票,給要進行選舉的 slave 進行投票,若是大部分 master node(N/2 + 1)
都投票給了某個從節點,那麼選舉經過,那個從節點能夠切換成 master。
從節點執行主備切換,從節點切換爲主節點。
整個流程跟哨兵相比,很是相似,因此說,redis cluster 功能強大,直接集成了 replication 和 sentinel 的功能。