Redis 低成本的可用設計
Redis Sentinel
-
Sentinel 介紹
-
Sentinel 配置
-
故障轉移消息接收的 3 種方式
-
腳本接收
-
客戶端直接接收
-
服務間接接收
-
整體設計
-
總結
關於 Redis 高可用方案,看到較多的是 keepalived、zookeeper 方案。keepalived 是主備模式,意味着總有一臺浪費着。zookeeper 工作量成本偏高。本文主要介紹下使用官方 sentinel 做 redis 高可用方案的設計。
Sentinel 介紹
Sentinel 是 Redis 官方爲集羣提供的高可用解決方案。在實際項目中可以使用 sentinel 去做 redis 自動故障轉移,減少人工介入的工作量。另外 sentinel 也給客戶端提供了監控消息的通知,這樣客戶端就可根據消息類型去判斷服務器的狀態,去做對應的適配操作。
下面是 Sentinel 主要功能列表:
-
Monitoring:Sentinel 持續檢查集羣中的 master、slave 狀態,判斷是否存活。
-
Notification:在發現某個 redis 實例死的情況下,Sentinel 能通過 API 通知系統管理員或其他程序腳本。
-
Automatic failover:如果一個 master 掛掉後,sentinel 立馬啓動故障轉移,把某個 slave 提升爲 master。其他的 slave 重新配置指向新 master。
-
Configuration provider:對於客戶端來說 sentinel 通知是有效可信賴的。客戶端會連接 sentinel 去請求當前 master 的地址,一旦發生故障 sentinel 會提供新地址給客戶端。
Sentinel 配置
Sentinel 本質上只是一個運行在特殊模式下的 redis 服務器,通過不同配置來區分提供服務。sentinel.conf 配置:
// [監控名稱] [ip] [port] [多少sentinel同意才發生故障轉移]
sentinel monitor mymaster 127.0.0.1 6379 2
// [監控名稱] [Master多少毫秒後不迴應ping命令,就認爲master是主觀下線狀態]
sentinel down-after-milliseconds mymaster 60000
// [故障轉移超時時間]
sentinel failover-timeout mymaster 180000
//[在執行故障轉移時,最多可以有多少個從服務器同時對新的主服務器進行同步]
sentinel parallel-syncs mymaster 1
sentinel 需要使用 redis2.8 版本以上,啓動如下:
redis-sentinel sentinel.conf
啓動後 Sentinel 會:
-
以 10 秒一次的頻率,向被監視的 master 發送 info 命令,根據回覆獲取 master 當前信息。
-
以 1 秒一次的頻率,向所有 redis 服務器、包含 sentinel 在內發送 PING 命令,通過回覆判斷服務器是否在線。
-
以 2 秒一次的頻率,通過向所有被監視的 master,slave 服務器發送包含當前 sentinel,master 信息的消息。
另外建議 sentinel 至少起 3 個實例以上,並配置 2 個實例同意即可發生轉移。5 個實例,配置 3 個實例同意以此類推。
Redis 服務器一旦發送故障後,sentinel 通過 raft 算法投票選舉新 master。故障轉移過程可以通過 sentinel 的 API 獲取 / 訂閱接收事件消息。
腳本接收
// 當故障轉移期間,可以指定一個 “通知” 腳本用來告知系統管理員,當前集羣的情況。// 腳本被允許執行的最大時間爲 60 秒,如果超時,腳本將會被終止(KILL)
sentinel notification-script mymaster /var/redis/notify.sh
// 故障轉移期之後,配置通知客戶端的腳本.
sentinel client-reconfig-script mymaster /var/redis/notifyReconfig.sh
客戶端直接接收
Sentinel 的故障轉移消息通知使用的是 redis 發佈訂閱 (詳解 Redis 發佈訂閱及客戶端編程)。就是說在故障轉移期間所有產生的事件信息,都通過頻道(channel) 發佈出去。比如我們加臺 slave 服務器,sentinel 監聽到後會發佈加 slave 的消息到 "+slave" 頻道上,客戶端只需要訂閱 "+slave" 頻道即可接收到對應消息。
其消息格式如下:[實例類型] [事件服務器名稱] [服務器 ip] [服務器端口] @[master 名稱] [ip] [端口]
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
通知消息格式示例:
* //訂閱類型, *即訂閱所有事件消息。
-sdown //消息類型
slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381
訂閱消息示例:
using (RedisSentinel rs = new RedisSentinel(CurrentNode.Host, CurrentNode.Port))
{
var redisPubSub = new RedisPubSub(node.Host, node.Port);
redisPubSub.OnMessage += OnMessage;
redisPubSub.OnSuccess += (msg) =>{};
redisPubSub.OnUnSubscribe += (obj) =>{};
redisPubSub.OnError = (exception) =>{ };
redisPubSub.PSubscribe("*");
}
服務間接接收
這種方式在第二種基礎上擴展了一層,即應用端不直接訂閱 sentinel。單獨做服務去幹這件事情,然後應用端提供 API 供這個服務回調通知。這樣做的好處在於:
-
減少應用端監聽失敗出錯的可能性。
-
應用端由主動方變成被動方,降低耦合。
-
性能提高,輪詢變回調。
-
獨立成服務可擴展性更高。
比如:
1:以後換掉 sentinel,我們只需要動服務即可,應用端無需更改。
2:可以在服務內多增加一層守護線程去主動拉取 redis 狀態,這樣可確保即使 sentinel 不生效,也能及時察覺 redis 狀態,並通知到應用端。當然這種情況很極端,因爲 sentinel 配的也是多節點,同時掛的幾率非常小。示例:應用端提供回調 API,在這個 API 邏輯下去刷新內存中的 Redis 連接。
http://127.0.0.1/redis/notify.api
獨立服務監控到狀況後,調用 API 通知應用端:
httprequest.post("http://127.0.0/redis/notify.api");
推薦使用第三種,其整體流程圖如下:
各種 sentinel 通知消息類型見官方文檔,項目中使用的 redis 客戶端在 github 上 [HRedis]。本文分享了樓主在項目中做 Redis 高可用的經驗,希望對大家有所幫助。在人力物力滿足的情況下還是推薦使用 zookeeper 方案的。只有三五杆槍的情況下也就退而求其次,利用最小成本滿足需求並保留可擴展性。
相信沒有最好的架構,只有更合適的架構。
如果您喜歡本文,歡迎點擊右上角,把文章分享到朋友圈~~
如果有想了解和學習的知識點或技術點,也可以留言給若飛安排分享
作者: 蘑菇先生
來源: cnblogs.com/mushroom/p/4526912.html
版權申明:內容來源網絡,版權歸原創者所有。除非無法確認,我們都會標明作者及出處,如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/BKIl-WugGlD96rLdhEo3Ug