Redis低成本高可用方案設計

點擊上方「全棧程序員社區」,星標公衆號
html

重磅乾貨,第一時間送達


做者:蘑菇先生node

cnblogs.com/mushroom/p/4526912.htmlgit

關於Redis高可用方案,看到較多的是keepalived、zookeeper方案。keepalived是主備模式,意味着總有一臺浪費着。zookeeper工做量成本偏高。程序員

本文主要介紹下使用官方sentinel作redis高可用方案的設計。github

閱讀目錄:web

  1. Redis Sentinel面試

  2. 故障轉移消息接收的3種方式redis

  3. 總體流程圖算法

  4. 總結後端

Redis Sentinel

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個實例贊成以此類推。

故障轉移消息接收的3種方式

Redis服務器一旦發送故障後,sentinel經過raft算法投票選舉新master。故障轉移過程能夠經過sentinel的API獲取/訂閱接收事件消息。

搜索Java知音公衆號,回覆「後端面試」,送你一份Java面試題寶典.pdf

腳本接收

  • 當故障轉移期間,能夠指定一個「通知」腳本用來告知系統管理員,當前集羣的狀況。
  • 腳本被容許執行的最大時間爲60秒,若是超時,腳本將會被終止(KILL)
sentinel notification-script mymaster /var/redis/notify.sh 
  • 故障轉移期以後,配置通知客戶端的腳本.
sentinel client-reconfig-script mymaster /var/redis/notifyReconfig.sh 

客戶端直接接收

Sentinel的故障轉移消息通知使用的是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上

https://github.com/mushroomsir/HRedis

本文分享了樓主在項目中作Redis高可用的經驗,但願對你們有所幫助。在人力物力知足的狀況下仍是推薦使用zookeeper方案的。只有三五杆槍的狀況下也就退而求其次,利用最小成本知足需求並保留可擴展性。 

相信沒有最好的架構,只有更合適的架構。

  • http://redis.io/topics/sentinel

本文分享自微信公衆號 - 全棧程序員社區(mush_it)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索