一、Redis Cluster
1、集羣
(1)單個redis存在不穩定性。當redis服務宕機了,就沒有可用的服務了。
(2)單個redis的讀寫能力是有限的。
2、數據分佈
分佈式數據庫首先要解決把整個數據集按照分區規則映射到多個節點的問題, 即把數據集劃分到多個節點上, 每個節點負責整體數據的一個子集。
常用的分區方式:
順序分區和哈希分區
哈希分區:
- 節點取餘。使用特定的數據,如 Redis 的 鍵 或 用戶 ID,再根據 節點數量 N 使用公式:hash(key)% N 計算出 哈希值,用來決定數據 映射 到哪一個節點上。
優點
這種方式的突出優點是 簡單性,常用於 數據庫 的 分庫分表規則。
缺點
當 節點數量 變化時,如 擴容 或 收縮 節點,數據節點 映射關係 需要重新計算,會導致數據的 重新遷移。建議翻倍擴容。
- 一致性哈希分區 一致性哈希 可以很好的解決 穩定性問題,可以將所有的 存儲節點 排列在 首尾相接 的 Hash 環上,每個 key 在計算 Hash 後會 順時針 找到 臨近的 存儲節點 存放。而當有節點 加入 或 退出 時,僅影響該節點在 Hash 環上 順時針相鄰 的 後續節點,但還是有數據遷移。
- 虛擬槽分區
槽是集羣內數據管理和遷移的基本單位。 採用大範圍槽的主要目的是爲了方便數據拆分和集羣擴展。當前集羣有 5 個節點,每個節點平均大約負責 3276 個 槽。由於採用 高質量 的 哈希算法,每個槽所映射的數據通常比較 均勻,將數據平均劃分到 5 個節點進行 數據分區。Redis Cluster 就是採用 虛擬槽分區。
這種結構很容易 添加 或者 刪除 節點。如果 增加 一個節點 6,就需要從節點 1 ~ 5 獲得部分 槽 分配到節點 6 上。如果想 移除 節點 1,需要將節點 1 中的 槽 移到節點 2 ~ 5 上,然後將 沒有任何槽 的節點 1 從集羣中 移除 即可。
由於從一個節點將 哈希槽 移動到另一個節點並不會 停止服務,所以無論 添加刪除或者 改變 某個節點的 哈希槽的數量 都不會造成 集羣不可用 的狀態.
3、搭建集羣
單機架構:
分佈式架構:
節點間彼此通信,每個節點都可以讀寫
節點通信採用P2P的Gossip(流言)協議,原理就是節點之間不斷通信交換信息,一段時間以後多有的節點都會知道集羣完整的信息。
Gossip消息:
- ping消息
集羣內交換最頻繁的消息, 集羣內每個節點每秒向多個其他節點發送ping消息, 用於檢測節點是否在線和交換彼此狀態信息。 ping消息發送封裝了自身節點和部分其他節點的狀態數據。 - pong消息
當接收到ping、 meet消息時, 作爲響應消息回覆給發送方確認消息正常通信。 pong消息內部封裝了自身狀態數據。 節點也可以向集羣內廣播自身的pong消息來通知整個集羣對自身狀態進行更新。 - meet消息
用於通知新節點加入。 消息發送者通知接收者加入到當前集羣, meet消息通信正常完成後, 接收節點會加入到集羣中並進行週期性的ping、 pong消息交換。 - fail消息
當節點判定集羣內另一個節點下線時, 會向集羣內廣播一個fail消息, 其他節點接收到fail消息之後把對應節點更新爲下線狀態。
優點:
①主從複製,每一個主節點都有一個從節點
②高可用,主節點故障後,會自動故障轉移
③分片
4、集羣伸縮
①伸縮原理
每個節點把一部分槽和數據遷移到新的節點6385, 每個節點負責的槽和數據相比之前變少了從而達到了集羣擴容的目的。
擴展:啓動一個服務,和其他節點握手(meet),然後進行槽的分配,然後進行槽(slot)的中數據的遷移。
集羣伸縮=槽和數據在節點之間的移動。
②擴容集羣
- 準備新節點:開啓新的redis服務
- 加入集羣(meet)>>>cluster meet:上述準備的新節點加入到集羣中。
- 遷移槽
槽遷移計劃 : 平均槽數量,平均分配16384個槽到各個節點。
- 遷移數據:
遷移數據③縮容集羣
步驟:1、下線遷移槽,2、忘記節點(下線的節點和其他節點斷開聯繫,cluster forget {downNodeId}),關閉節點
5、客戶端路由
①moved重定向
在集羣模式下, Redis接收任何鍵相關命令時首先計算鍵對應的槽, 再根據槽找出所對應的節點, 如果節點是自身, 則處理鍵命令; 否則回覆MOVED重定向錯誤, 通知客戶端請求正確的節點。
節點對於不屬於它的鍵命令只回復重定向響應, 並不負責轉發。
②ask重定向
moved和ask的區別:兩者都是客戶端重定向;moved已經確定遷移;ask,槽還在遷移中。
③smart客戶端
6、故障轉移
redis-cluster不需要使用redis sentinel,redis每個節點之間互相監控。redis集羣自身實現了高可用。
1、故障發現
Redis集羣內節點通過ping/pong消息實現節點通信, 消息不但可以傳播節點槽信息, 還可以傳播其他狀態如: 主從狀態、 節點故障等。 因此故障發現也是通過消息傳播機制實現的, 主要環節包括: 主觀下線(pfail) 和客觀下線(fail) 。
主觀下線簡單來講就是, 當cluster-note-timeout時間內某節點無法與另一個節點順利完成ping消息通信時, 則將該節點標記爲主觀下線狀態。 每個節點內的cluster State結構都需要保存其他節點信息, 用於從自身視角判斷其他節點的狀態。
當某個節點判斷另一個節點主觀下線後, 相應的節點狀態會跟隨消息在集羣內傳播。 ping/pong消息的消息體會攜帶集羣1/10的其他節點狀態數據,當接受節點發現消息體中含有主觀下線的節點狀態時, 會在本地找到故障節點ClusterNode結構, 保存到下線報告鏈表中。
通過Gossip消息傳播, 集羣內節點不斷收集到故障節點的下線報告。 當半數以上持有槽的主節點都標記某個節點是主觀下線時。 觸發客觀下線流程。2、故障恢復
步驟:
- 資格檢查;
每個從節點檢查與故障主節點的斷線時間。超過一定時間(默認150s)就取消資格。- 準備選舉時間;
對從節點中,偏移量最大的,設置更小的延遲,以便這個從節點稱爲新的master。意思就是:誰偏移量大,誰提前觸發選舉流程。- 選舉投票;
只有持有槽的主節點纔會處理故障選舉消息。
投票過程其實是一個領導者選舉的過程, 如集羣內有N個持有槽的主節點代表有N張選票。 由於在每個配置紀元內持有槽的主節點只能投票給一個從節點, 因此只能有一個從節點獲得N/2+1的選票, 保證能夠找出唯一的從節點。
- 替換主節點。
1、把當前從節點取消複製變爲主節點(slaveof no one)。
2、執行clusterDelSlot撤銷故障主節點負責的槽,並執行clusterAddSlot把這些槽分配給自己。
3、向集羣廣播自己的pong消息,表明已經替換了故障節點。
7、常見問題
1、集羣完整性
cluster-require-full-coverage 默認設置爲yes,即集羣中16384個槽全部可用,纔對外提供服務。
建議設置爲no
2、帶寬消耗
集羣內Gossip消息通信本身會消耗帶寬, 官方建議集羣最大規模在1000以內。單集羣不適合部署超大規模的節點。 集羣內所有節點通過ping/pong消息彼此交換信息。
3、Pub/Sub廣播
在集羣模式下內部實現對所有的publish命令都會向所有的節點進行廣播, 造成每條publish數據都會在集羣內所有節點傳播一次, 加重帶寬負擔。
4、集羣傾斜
數據傾斜
- 節點和槽分配不均
- 不同槽對應鍵值數量差異較大
- 包含bigkey
- 內存相關配置不一致
請求傾斜
- 熱點key:重要的key或者bigkey
5、讀寫分離
集羣模式的從節點不接受任何讀寫請求 。
6、數據遷移
7、集羣和單機的比較
集羣:批量操作支持有限,例如mget,mset必須在一個slot;不支持多數據庫,只有db0;……
單機:
redis cluster,在很多情況下,並不一定需要。很多場景下,redis sentinel已經足夠好。
二、redis集羣搭建
1、原生命令安裝
- 配置開啓節點,配置6個,開啓6個服務。節點啓動
- meet,節點握手
cluster meet ip port 分別握手 redis-cli -p 7000 cluster meet 127.0.0.1 7001 redis-cli -p 7000 cluster meet 127.0.0.1 7002 redis-cli -p 7000 cluster meet 127.0.0.1 7003 redis-cli -p 7000 cluster meet 127.0.0.1 7004 redis-cli -p 7000 cluster meet 127.0.0.1 7005
集羣已經互通
- 指派槽
cluster addslots slot [slot ...] shell命令,分配槽 start=$1 end=$2 port=$3 for slot in `seq ${start} ${end}` do redis-cli -p ${port} cluster addslots ${slot} done
- 主從關係,把7003當做7000的從節點,依次
cluster replicate node-id redis-cli -p 7003 cluster replicate node-id #把7003當做某個的從節點
2、官方
1、Ruby環境準備
安裝ruby:https://www.cnblogs.com/xuliangxing/p/7132656.html?utm_source=itdadao&utm_medium=referral
安裝rubygem redis依賴:
拷貝redis-trib.rb到集羣根目錄
redis-trib.rb 是 redis 官方推出的管理 redis 集羣 的工具,集成在 redis 的源碼 src 目錄下,將基於 redis 提供的 集羣命令 封裝成 簡單、便捷、實用 的 操作工具。
cp ./redis-trib.rb /usr/local/bin
2、redis-trib進行集羣搭建
啓動 6 臺 redis 節點,配置和手動執行的配置一樣。
sudo ./redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6389 127.0.0.1:6390 127.0.0.1:6391
集羣創建後,redis-trib 會先將 16384 個 哈希槽 分配到 3 個 主節點,即 redis-6379,redis-6380 和 redis-6381。然後將各個 從節點 指向 主節點,進行 數據同步。