redis — 集羣模式與原理介紹(一)

1 簡介

Redis 提供數據緩存服務,內部數據都存在內存中,所以訪問速度非常快。

服務模式

1.1 主從模式/單機模式

早期,Redis單應用服務亦能滿足企業的需求。之後,業務量的上升,單機的讀寫能力滿足不了業務的需求,技術上實現主從服務,並讀寫分離,分擔主 Master 的讀負擔。
Redis 單機模式下,即便是“1主 N 備”結構,當主節點故障時,備節點也無法自動升主,即無法自動故障轉移(Failover)。
在這裏插入圖片描述

1.2 哨兵模式

故障轉移需要“哨兵”Sentinel 輔助,Sentinel 是 Redis 高可用的解決方案,由一個或者多個 Sentinel 實例組成的系統可以監視 Redis 主節點及其從節點,當檢測到 Redis 主節點下線時,會根據特定的選舉規則從該主節點對應的所有從節點中選舉出一個“最優”的從節點升主,然後由升主的新主節點處理請求。
在這裏插入圖片描述
哨兵本身是一個小集羣,Redis 本身爲一主多從。哨兵模式只提供單一節點(主節點)對外服務,當主節點出現問題時,將出現瞬斷問題,在進行選舉時,不能提供服務;
哨兵兩兩通訊,Redis 兩兩通訊,哨兵與 Redis 間兩兩通訊。哨兵與 Redis 節點間,都是通過心跳來監控狀態,哨兵本身就是一個小集羣;
每個哨兵監控所有主從節點。哨兵監控着 Redis 的運行狀況,確定主節點以及從節點,保存清單,當主節點掛掉時,進行主節點的選舉,更新服務列表;
Server 首先通過哨兵(Sentinel)來確定訪問那臺 Redis 服務器 服務端使用 Redis 時,優先訪問哨兵集羣,獲取可訪問的 Redis 服務的 IP 和端口。

1.3 集羣模式

在這裏插入圖片描述
集羣對外統一。在使用集羣時,只需要關注 Redis 各個節點的 IP 和端口,至於讀寫節點、主從等無需關注;
集羣內部協調。主從節點在集羣部署時已選舉完成,除非節點掛掉,會進行重新選舉。其次刪除相關配置項時,也會重新選舉主節點;
去中心化。本模式不再如哨兵、Codise 等,需要第三方監控。Cluster自行加入選舉,完成主節點選舉,以及讀寫訪問控制。

原理介紹
  • 選舉
    集羣啓動後,主從已分配完成,經過了 N 輪的選舉。當某一個主節點宕機,那麼從節點需要經過選舉成爲主節點。簡單介紹選舉過程:
    所有子節點向其他節點發送請求,請求自身成爲主節點,其他節點收到請求後,返回投票信息,只有主節點 master 有權投票,且只能投一次,當獲取到的票數大於一半人數時(master 個數),就當選 master。
    期間,所有子節點發送請求的時機有所有不同。所以基本都有先後順序,所以很少會出現票數相同情況,如果相同,則重新選舉,直到選出 master 爲止。
    故,需要至少 3 主 3 從,否則節點出現問題,將選舉失敗。
  • 槽位
    在 Redis 集羣中,定義了 16384 個邏輯上的槽位。將這些槽位均勻分配給 N 個節點(一主一從爲一個節點),此文 3 個節點,自動均勻分配。意思爲,0-5460 個槽位分配給第一個節點。
    當用戶 set 一個值時,除了計算 key 本身的 hashCode 之外,還會調用 C 語言的一個 CRC16 算法,將 key 當 hash 值再計算出一個數字,然後與 16384 取模,得到的數字落在哪個槽位,則會將數據放在對應的節點。
    比如,計算出的數字爲 16387,則取模 16384 後,得到 3,在 0-5460 之間,則放入對於的第一個節點。其他以此類推。
  • 跳轉
    大家都知道,主從模式中,只有主節點可以寫入數據,而從節點只能讀取數據。在 Cluster 集羣中,設置值時,如果計算出的槽位在另一臺服務器上,則集羣連接會自動跳轉至相應服務器。
  • 網絡抖動
    網絡抖動,表示網絡很不穩定。當出現這樣的情況,可能一小段時間連接不上,可能就認爲了節點掛了。這裏就涉及到連接到超時時間,在網絡不穩定的情況下,可以將超時時間設置長一些。
特點
  • 節點互通:所有的 Redis 節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬;
  • 去中心化:Redis Cluster 不存在中心節點,每個節點都記錄有集羣的狀態信息,並且通過 Gossip 協議,使每個節點記錄的信息實現最終一致性;
  • 客戶端直連:客戶端與 Redis 節點直連,不需要中間 Proxy 層,客戶端不需要連接集羣所有節點,連接集羣中任何一個可用節點即可;
  • 數據分片:Redis Cluster 的鍵空間被分割爲 16384 個 Slot,這些 Slot 被分別指派給主節點,當存儲 Key-Value 時,根據 CRC16(key) Mod 16384的值,決定將一個 Key-Value 放到哪個 Slot 中;
  • 多數派原則:對於集羣中的任何一個節點,需要超過半數的節點檢測到它失效(pFail),纔會將其判定爲失效(Fail);
  • 自動 Failover:當集羣中某個主節點故障後(Fail),其它主節點會從故障主節點的從節點中選舉一個“最佳”從節點升主,替代故障的主節點;
  • 功能弱化:集羣模式下,由於數據分佈在多個節點,不支持單機模式下的集合操作,也不支持多數據庫功能,集羣只能使用默認的0號數據庫;
  • 集羣規模:官方推薦的最大節點數量爲 1000 個左右,這是因爲當集羣規模過大時,Gossip 協議的效率會顯著下降,通信成本劇增。
分片

Redis 集羣實現的基礎是分片,即將數據集有機的分割爲多個片,並將這些分片指派給多個 Redis 實例,每個實例只保存總數據集的一個子集。利用多臺計算機內存和來支持更大的數據庫,而避免受限於單機的內存容量;通過多核計算機集羣,可有效擴展計算能力;通過多臺計算機和網絡適配器,允許我們擴展網絡帶寬。
基於“分片”的思想,Redis 提出了 Hash Slot。Redis Cluster 把所有的物理節點映射到預先分好的16384個 Slot 上,當需要在 Redis 集羣中放置一個 Key-Value 時,根據 CRC16(key) Mod 16384的值,決定將一個 Key 放到哪個 Slot 中。
在這裏插入圖片描述

請求路由方式

客戶端直連 Redis 服務,進行讀寫操作時,Key 對應的 Slot 可能並不在當前直連的節點上,經過“重定向”才能轉發到正確的節點。客戶端進行 Set 操作,當 Key 對應的 Slot 不在當前節點時,客戶端會報錯並返回正確節點的 IP 和端口。Set 成功則返回 OK。

以集羣模式登錄 127.0.0.1:6379 客戶端(注意命令的差別:-c 表示集羣模式),則可以清楚的看到“重定向”的信息,並且客戶端也發生了切換:“6379” -> “6381”。
在這裏插入圖片描述
Redis Cluster 藉助客戶端實現的請求路由是一種混合形式的查詢路由,它並非從一個 Redis 節點到另外一個 Redis,而是藉助客戶端轉發到正確的節點。
實際應用中,可以在客戶端緩存 Slot 與 Redis 節點的映射關係,當接收到 MOVED 響應時修改緩存中的映射關係。如此,基於保存的映射關係,請求時會直接發送到正確的節點上,從而減少一次交互,提升效率。

節點通信原理:Gossip 算法

在分佈式系統中,需要提供維護節點元數據信息的機制,所謂元數據是指節點負責哪些數據、主從屬性、是否出現故障等狀態信息。常見的元數據維護方式分爲集中式和無中心式。Redis Cluster 採用 Gossip 協議實現了無中心式。
Redis Cluster 中的每個 Redis 實例監聽兩個 TCP 端口,6379(默認)用於服務客戶端查詢,16379(默認服務端口+10000)用於集羣內部通信。集羣中節點通信方式如下:

  • 每個節點在固定週期內通過特定規則選擇幾個節點發送 Ping 消息;
  • 接收到 Ping 消息的節點用 Pong 消息作爲響應。
1.節點間是如何交換信息的

Redis 節點啓動之後,會每間隔 100ms 執行一次集羣的週期性函數 clusterCron()。
一、當前節點向另一個節點發送 Ping 消息時,攜帶的其它節點的消息數量至少爲3,最大等於集羣節點總數-2;
二、爲 Ping 消息體中選擇攜帶的其它節點的信息時,採用的是混合選擇模式:隨機選擇+偏好性選擇,這樣不僅可以保證 Gossip 協議隨機傳播的原則,還可以儘量將當前節點掌握的其它節點的故障信息傳播出去。

2.如何保證消息傳播的效率

前面已經提到,集羣的週期性函數 clusterCron() 執行週期是 100ms,爲了保證傳播效率,每10個週期,也就是 1s,每個節點都會隨機選擇5個其它節點,並從中選擇一個最久沒有通信的節點發送 ing消息。
當然,這樣還是沒法保證效率,畢竟5個節點是隨機選出來的,其中最久沒有通信的節點不一定是全局“最久”。因此,對哪些長時間沒有“被” 隨機到的節點進行特殊照顧:每個週期(100ms)內掃描一次本地節點列表,如果發現節點最近一次接受 Pong 消息的時間大於 cluster_node_timeout/2,則立刻發送 Ping 消息,防止該節點信息太長時間未更新。
cluster_node_timeout 參數對消息發送的節點數量影響非常大。當帶寬資源緊張時,可以適當調大這個參數,如從默認15秒改爲30秒來降低帶寬佔用率。但是,過度調大 cluster_node_timeout 會影響消息交換的頻率從而影響故障轉移、槽信息更新、新節點發現的速度,因此需要根據業務容忍度和資源消耗進行平衡。同時整個集羣消息總交換量也跟節點數成正比。
每個 Ping 消息的數據量體現在消息頭和消息體中,其中消息頭空間佔用相對固定。消息體會攜帶一定數量的其它節點信息用於信息交換,消息體攜帶數據量跟集羣的節點數息息相關,更大的集羣每次消息通信的成本也就更高,因此對於 Redis 集羣來說並不是越大越好。

故障轉移

Redis Cluster 的故障轉移可劃分爲三大步驟:故障檢測、從節點選舉以及故障倒換,以下詳細介紹。

  • 故障檢測

  • 單點視角檢測
    集羣中的每個節點都會定期通過集羣內部通信總線向集羣中的其它節點發送 Ping 消息,用於檢測對方是否在線。如果接收 Ping 消息的節點沒有在規定的時間內向發送 Ping 消息的節點返回 Pong 消息,那麼,發送 Ping 消息的節點就會將接收 Ping 消息的節點標註爲疑似下線狀態(Probable Fail,Pfail)。

  • 檢測信息傳播
    集羣中的各個節點會通過相互發送消息的方式來交換自己掌握的集羣中各個節點的狀態信息,如在線、疑似下線(Pfail)、下線(Fail)。例如,當一個主節點 A 通過消息得知主節點 B 認爲主節點 C 疑似下線時,主節點 A 會更新自己保存的集羣狀態信息,將從 B 獲得的下線報告保存起來。

  • 基於檢測信息作下線判決
    如果在一個集羣裏,超過半數的持有 Slot(槽)的主節點都將某個主節點 X 報告爲疑似下線,那麼,主節點 X 將被標記爲下線(Fail),並廣播出去,所有收到這條 Fail 消息的節點都會立即將主節點 X 標記爲 Fail。至此,故障檢測完成。

  • 選舉
    主節點被標記爲 Fail 後,對應的從節點會發起投票,競爭升主。

  • 從節點拉票
    當從節點發現自己複製的主節點狀態爲已下線時,從節點就會向集羣廣播一條請求消息,請求所有收到這條消息並且具有投票權的主節點給自己投票。

  • 拉票優先級
    從節點在發現其主節點下線時,並非立即發起故障轉移流程而進行“拉票”的,而是要等待一段時間,在未來的某個時間點才發起選舉。
    mstime() + 500ms + random()%500ms + rank*1000ms
    rank即排名,排名是指當前從節點在下線主節點的所有從節點中的排名,排名主要是根據複製數據量來定,複製數據量越多,排名越靠前,因此,具有較多複製數據量的從節點可以更早發起故障轉移流程,從而更可能成爲新的主節點。

  • 主節點投票
    如果一個主節點具有投票權(負責處理 Slot 的主節點),並且這個主節點尚未投票給其它從節點,那麼這個主節點將向請求投票的從節點返回一條迴應消息,表示支持該從節點升主。

  • 根據投票結果決策
    在一個具有 N 個主節點投票的集羣中,理論上每個參與拉票的從節點都可以收到一定數量的主節點投票,但是,在同一輪選舉中,只可能有一個從節點收到的票數大於 N/2 + 1,也只有這個從節點可以升級爲主節點,並代替已下線的主節點繼續工作。

  • 選舉失敗
    沒有一個候選從節點獲得超過半數的主節點投票。遇到這種情況,集羣將會進入下一輪選舉,直到選出新的主節點爲止。

  • 選舉算法
    選舉新主節點的算法是基於 Raft 算法的 Leader Election 方法來實現的。

  • 故障轉移
    選舉完成後,獲勝的從節點將發起故障轉移(Failover),角色從 Slave 切換爲 Master,並接管原來主節點的 Slots,詳細過程如下。
    新的主節點會通過輪詢所有 Slot,撤銷所有對已下線主節點的 Slot 指派,消除影響,並且將這些 Slot 全部指派給自己。
    新的主節點會向集羣中廣播一條 Pong 消息,將自己升主的信息通知到集羣中所有節點。
    新的主節點開始處理自己所負責 Slot 對應的請求,至此,故障轉移完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章