redis客戶端實現高可用讀寫分離

mushishi發表於2021-07-02

背景

(1) redis單機的讀寫效能輕鬆上大幾萬,不過線上環境不會只部署光禿禿的一個節點,還是會配合 sentinel 再部署一個 slave作為高可用節點的;
但是standby的slave節點是不對外提供服務端的,一定程度上造成了浪費資源

(2) 當業務不斷髮展,原來單節點快取的資料(如,商品資訊快取、配置資訊等)的查詢qps不斷升高(寫qps增長不多),突破十幾萬、幾十萬的的時候,此時一個節點就扛不住了,我們就需要增加幾個redis slaves節點來分擔這些查詢的壓力 也就是讀寫分離

但是,常用的 redis 客戶端jedis並不支援讀寫分離能力

實現方式

(1) 從配置中心獲取 master 和 slaves 的連線資訊,分別初始化好一個連線master的寫連線池和一組slave的讀連線池
(2) 將命令進行分類:執行寫命令則從 master的連線池取連線然後執行,如果是讀命令則從slave的連線池中取出連線執行
可能有多個slave節點,可以按照一定的策略進行負載均衡(權重、隨機、輪詢...etc) 從其中一個 slave節點的連線池獲取連線

大概長這樣:
read-write-split

高可用版本

前面的實現方式正常情況下是可以的

但是:
(1) 如果執行期間 master掛了怎麼辦? 如何自動 failover 切換?
(2) 如果流量突增,需要動態擴容一個或多個 slave節點,如何動態生效?

那就不能從配置檔案取master和slaves的 ip+port 了,得從redis ha的元件去動態獲取 當前master 和可用slave列表的節點資訊 => sentinel

1.初始化

向 sentinel 傳送命令獲取master和slaves的節點資訊

SENTINEL get-master-addr-by-name <masterName>  //獲取當前masterName標識的當前master節點資訊,哨兵可監控多個 mater ha,所以要用<masterName>區分
SENTINEL slaves <masterName> //獲取可用的slaves列表資訊

初始化-獲取連線
拿到連線後,繼續用開頭的方式去建立連線池就行了

2. 動態failover、擴容

初始化完畢後,在執行期間master節點,和slaves還是可能變化的, 如
(1) master故障、網路分割槽,sentinel 提升一個slave為新的master
(2) 新增slave節點應對突增流量

我們如何能不重啟客戶端的情況下,動態切換?

sentinel 在進行master切換、slave變更等操作的時候都會向對應的 channel 釋出事件,我們可以基於這些事件感知到相應的變化
參考: https://redis.io/topics/sentinel#pubsub-messages

2.1 failover切換 master

當 sentinel 進行master failover切換的時候,它會向channel: switch-master 傳送通知,我們在客戶端訂閱這個channel,收到事件後,重新進行初始化的步驟即可
監聽master切換事件

2.2 擴容slave

當新的 slave 節點加入, sentinel 感知到則會向channel: +slave 釋出事件,我們監聽到後,重新獲取slaves節點資訊重建slaves的連線池就可以了(這邊不涉及master的變化)
監聽slave擴容事件

總結

基於 sentienl 獲取和動態感知 master、slaves節點資訊的變化,我們的讀寫分離客戶端就能具備高可用+動態擴容感知能力了;

相關文章