Redis Cluster數據分片機制

高級開發不得不懂的Redis Cluster數據分片機制

Redis 集羣簡介

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

Redis Cluster 通常由多個節點組成,節點數量至少爲 6 個才能保證組成完整高可用的集羣,其中三個爲主節點,三個爲從節點。三個主節點會分配槽,處理客戶端的命令請求,而從節點可用在主節點故障後,頂替主節點。算法

高級開發不得不懂的Redis Cluster數據分片機制

如上圖所示,該集羣中包含 6 個 Redis 節點,3主3從,分別爲M1,M2,M3,S1,S2,S3。除了主從 Redis 節點之間進行數據複製外,全部 Redis 節點之間採用 Gossip 協議進行通訊,交換維護節點元數據信息。數據庫

通常來講,主 Redis 節點會處理 Clients 的讀寫操做,而從節點只處理讀操做。緩存

數據分片策略

分佈式數據存儲方案中最爲重要的一點就是數據分片,也就是所謂的 Sharding。分佈式

爲了使得集羣可以水平擴展,首要解決的問題就是如何將整個數據集按照必定的規則分配到多個節點上,經常使用的數據分片的方法有:範圍分片,哈希分片,一致性哈希算法和虛擬哈希槽等。ide

範圍分片假設數據集是有序,將順序相臨近的數據放在一塊兒,能夠很好的支持遍歷操做。範圍分片的缺點是面對順序寫時,會存在熱點。好比日誌類型的寫入,通常日誌的順序都是和時間相關的,時間是單調遞增的,所以寫入的熱點永遠在最後一個分片。函數

高級開發不得不懂的Redis Cluster數據分片機制

對於關係型的數據庫,由於常常性的須要表掃描或者索引掃描,基本上都會使用範圍的分片策略。學習

Redis Cluster 採用虛擬哈希槽分區,全部的鍵根據哈希函數映射到 0 ~ 16383 整數槽內,計算公式:slot = CRC16(key) & 16383。每個節點負責維護一部分槽以及槽所映射的鍵值數據。

Redis 虛擬槽分區的特色:

  • 解耦數據和節點之間的關係,簡化了節點擴容和收縮難度。
  • 節點自身維護槽的映射關係,不須要客戶端或者代理服務維護槽分區元數據
  • 支持節點、槽和鍵之間的映射查詢,用於數據路由,在線集羣伸縮等場景。

高級開發不得不懂的Redis Cluster數據分片機制

Redis 集羣提供了靈活的節點擴容和收縮方案。在不影響集羣對外服務的狀況下,能夠爲集羣添加節點進行擴容也能夠下線部分節點進行縮容。能夠說,槽是 Redis 集羣管理數據的基本單位,集羣伸縮就是槽和數據在節點之間的移動。

下面咱們就先來看一下 Redis 集羣伸縮的原理。而後再瞭解當 Redis 節點數據遷移過程當中或者故障恢復時如何保證集羣可用。

擴容集羣

爲了讓讀者更好的理解上線節點時的擴容操做,咱們經過 Redis Cluster 的命令來模擬整個過程。

高級開發不得不懂的Redis Cluster數據分片機制

當一個 Redis 新節點運行並加入現有集羣后,咱們須要爲其遷移槽和數據。首先要爲新節點指定槽的遷移計劃,確保遷移後每一個節點負責類似數量的槽,從而保證這些節點的數據均勻。

1) 首先啓動一個 Redis 節點,記爲 M4。 
2) 使用 cluster meet 命令,讓新 Redis 節點加入到集羣中。新節點剛開始都是主節點狀態,因爲沒有負責的>槽,因此不能接受任何讀寫操做,後續咱們就給他遷移槽和填充數據。
3) 對 M4 節點發送 cluster setslot { slot } importing { sourceNodeId } 命令,讓目標節點準備導入槽的數據。 >4) 對源節點,也就是 M1,M2,M3 節點發送 cluster setslot { slot } migrating { targetNodeId } 命令,讓源節>點準備遷出槽的數據。 
5) 源節點執行 cluster getkeysinslot { slot } { count } 命令,獲取 count 個屬於槽 { slot } 的鍵,而後執行步驟>六的操做進行遷移鍵值數據。
6) 在源節點上執行 migrate { targetNodeIp} " " 0 { timeout } keys { key... } 命令,把獲取的鍵經過 pipeline 機制>批量遷移到目標節點,批量遷移版本的 migrate 命令在 Redis 3.0.6 以上版本提供。
7) 重複執行步驟 5 和步驟 6 直到槽下全部的鍵值數據遷移到目標節點。 
8) 向集羣內全部主節點發送 cluster setslot { slot } node { targetNodeId } 命令,通知槽分配給目標節點。爲了>保證槽節點映射變動及時傳播,須要遍歷發送給全部主節點更新被遷移的槽執行新節點。

收縮集羣

收縮節點就是將 Redis 節點下線,整個流程須要以下操做流程。

1) 首先須要確認下線節點是否有負責的槽,若是是,須要把槽遷移到其餘節點,保證節點下線後整個集羣槽節點映射的完整性。 
2) 當下線節點再也不負責槽或者自己是從節點時,就能夠通知集羣內其餘節點忘記下線節點,當全部的節點忘記改節點後能夠正常關閉。

下線節點須要將節點本身負責的槽遷移到其餘節點,原理與以前節點擴容的遷移槽過程一致。

高級開發不得不懂的Redis Cluster數據分片機制

遷移完槽後,還須要通知集羣內全部節點忘記下線的節點,也就是說讓其餘節點再也不與要下線的節點進行 Gossip 消息交換。

Redis 集羣使用 cluster forget { downNodeId } 命令來說指定的節點加入到禁用列表中,在禁用列表內的節點再也不發送 Gossip 消息。

客戶端路由

在集羣模式下,Redis 節點接收任何鍵相關命令時首先計算鍵對應的槽,在根據槽找出所對應的節點,若是節點是自身,則處理鍵命令;不然回覆 MOVED 重定向錯誤,通知客戶端請求正確的節點。這個過程稱爲 MOVED 重定向。

須要注意的是 Redis 計算槽時並不是只簡單的計算鍵值內容,當鍵值內容包括大括號時,則只計算括號內的內容。好比說,key 爲 user:{10000}:books時,計算哈希值只計算10000。

MOVED 錯誤示例顯示的信息以下,鍵 x 所屬的哈希槽 3999 ,以及負責處理這個槽的節點的 IP 和端口號 127.0.0.1:6381 。 客戶端須要根據這個 IP 和端口號, 向所屬的節點從新發送一次 GET 命令請求。

 
   

因爲請求重定向會增長 IO 開銷,這不是 Redis 集羣高效的使用方式,而是要使用 Smart 集羣客戶端。Smart 客戶端經過在內部維護 slot 到 Redis 節點的映射關係,本地就能夠實現鍵到節點的查找,從而保證 IO 效率的最大化,而 MOVED 重定向負責協助客戶端更新映射關係。

Redis 集羣支持在線遷移槽( slot ) 和數據來完成水平伸縮,當 slot 對應的數據從源節點到目標節點遷移過程當中,客戶端須要作到智能遷移,保證鍵命令可正常執行。例如當 slot 數據從源節點遷移到目標節點時,期間可能出現一部分數據在源節點,而另外一部分在目標節點。

高級開發不得不懂的Redis Cluster數據分片機制

因此,綜合上述狀況,客戶端命令執行流程以下所示:

  • 客戶端根據本地 slot 緩存發送命令到源節點,若是存在鍵對應則直接執行並返回結果給客戶端。
  • 若是節點返回 MOVED 錯誤,更新本地的 slot 到 Redis 節點的映射關係,而後從新發起請求。
  • 若是數據正在遷移中,節點會回覆 ASK 重定向異常。格式以下: ( error ) ASK { slot } { targetIP } : { targetPort }

客戶端從 ASK 重定向異常提取出目標節點信息,發送 asking 命令到目標節點打開客戶端鏈接標識,再執行鍵命令。

ASK 和 MOVED 雖然都是對客戶端的重定向控制,可是有着本質區別。ASK 重定向說明集羣正在進行 slot 數據遷移,客戶端沒法知道何時遷移完成,所以只能是臨時性的重定向,客戶端不會更新 slot 到 Redis 節點的映射緩存。可是 MOVED 重定向說明鍵對應的槽已經明確指定到新的節點,所以須要更新 slot 到 Redis 節點的映射緩存。

故障轉移

當 Redis 集羣內少許節點出現故障時經過自動故障轉移保證集羣能夠正常對外提供服務。

當某一個 Redis 節點客觀下線時,Redis 集羣會從其從節點中經過選主選出一個替代它,從而保證集羣的高可用性。這塊內容並非本文的核心內容,感興趣的同窗能夠本身學習。

可是,有一點要注意。默認狀況下,當集羣 16384 個槽任何一個沒有指派到節點時整個集羣不可用。執行任何鍵命令返回 CLUSTERDOWN Hash slot not served 命令。當持有槽的主節點下線時,從故障發現到自動完成轉移期間整個集羣是不可用狀態,對於大多數業務沒法忍受這狀況,所以建議將參數 cluster-require-full-coverage 配置爲 no ,當主節點故障時隻影響它負責槽的相關命令執行,不會影響其餘主節點的可用性。

相關文章
相關標籤/搜索