Redis 哨兵模式(Sentinel)
上一篇我們介紹了 redis 主從節點之間的資料同步複製技術,通過一次全量複製和不間斷的命令傳播,可以達到主從節點資料同步備份的效果,一旦主節點宕機,我們可以選擇一個工作正常的 slave 成為新的主節點,並讓其他 slave 去同步它。
這是處理 redis 故障轉移的一個方式,但卻不具備生產實用性,因為畢竟是手動處理故障,而 redis 發生故障時間節點不可預知,我們需要一個自動監控元件幫我們自動處理故障轉移。
Redis 哨兵模式(Sentinel)就是一個自動地監控處理 redis 間故障節點轉移工作的一個「東西」,準確來說,Sentinel 其實是一個 redis 服務端程式,只不過執行在特殊的模式下,不提供資料儲存服務,只進行普通 redis 節點監控管理。
一、什麼是哨兵(Sentinel)
Sentinel 其實也是一個 redis 的服務端程式,它也會定時執行 serverCron 函式,只是裡面其他的程式用不到,用到的是對普通 redis 節點的監控以及故障轉移模組。
Sentinel 初始化的時候會清空原來的命令表,寫入自己獨有的命令進去,所以普通 redis 節點支援的資料讀寫命令,對 Sentinel 來說都是找不到命令,因為它根本就沒有初始化這些命令的執行器。
Sentinel 會定時的對自己監控的 master 執行 info 命令,獲取最新的主從關係,還會定時的給所有的 redis 節點發送 ping 心跳檢測命令,如果檢測到某個 master 無法響應了,就會在給其他 Sentinel 傳送訊息,主觀認為該 master 宕機,如果 Sentinel 叢集認同該 master 下線的人數達到一個值,那麼大家統一意見,下線該 master。
下線之前需要做的是找 Sentinel 叢集中的某一個來執行下線操作,這個步驟叫領導者選舉,選出來以後會從該 master 所有的 slave 節點中挑一個合適的作為新的 master,並讓其他 slave 重新同步新的 master。
其實以上我們就簡單的介紹了 Sentinel 是什麼,本質上做了哪些事情,等下我們會結合原始碼細說其中的細節實現。這裡我們再看下,如何配置並啟動一個 Sentinel 監控。(生產環境建議配置大於三個)
第一步,啟動一個普通的 redis server 節點:
這一步沒什麼好說的,我們啟動在一個預設的 6379 埠上。
第二步,啟動三個不同的 slave 節點:
第三步,編寫 sentinel 配置檔案:
我們解釋一下這幾條配置的含義,我們說過 Sentinel 其實是執行在特殊模式下的 redis server,所以它需要執行埠。緊接著我們通過命令 sentinel monitor mymaster 配置當前 sentinel 需要監控的主節點 redis 以及觸發客觀下線引數,sentinel down-after-milliseconds 配置了一個引數,master 最長響應時間,超過這個時間就主觀判斷它下線。
sentinel parallel-syncs 配置用於限制主從切換之後,最多的並行同步資料的從節點數量,因為我們知道,主從進行全量同步階段,從節點載入資料時是不提供服務的,如果這個引數越大,那麼主從切換完成的時間就越短,當然也會導致大量從節點不可提供讀服務,反之。
sentinel failover-timeout 配置了執行故障轉移的最大等待時間。
第四步,啟動 Sentinel:
使用命令,redis-sentinel [config],啟動三個 sentinel。
這樣的話,其實我們就完成了一個簡單的 sentinel 叢集配置,下面我們手動的讓 master 宕機,看看整個 sentinel 有沒有為我們做故障轉移。
從結果上看來,sentinel 自動為我們把原先的從節點 7003 設定為新的 master,具體過程我們不細說,等下結合原始碼詳細介紹,這裡我們應該大致對 sentinel 的實際應用有了大概的認識。
二、Sentinel 如何工作的
當我們使用命令 redis-sentinel 啟動 sentinel 的時候,
int main(int argc, char **argv) {
。。。。。
server.sentinel_mode = checkForSentinelMode(argc,argv);
。。。。。
if (server.sentinel_mode) {
initSentinelConfig();
initSentinel();
}
。。。。。
}
checkForSentinelMode 函式中會根據你的命令以及引數,檢查判斷是否是以 sentinel 模式啟動,如果是則返回 1,反之。如果是以 sentinel 啟動,則會進行一個 sentinel 的初始化操作。
void initSentinelConfig(void) {
server.port = REDIS_SENTINEL_PORT; //26379
}
initSentinelConfig 實際上就是初始化當前 sentinel 執行埠,預設是 26379。
void initSentinel(void) {
unsigned int j;
//清空普通redis-server下可用的命令表
dictEmpty(server.commands,NULL);
//載入sentinel需要的命令
for (j = 0; j < sizeof(sentinelcmds)/sizeof(sentinelcmds[0]); j++) {
int retval;
struct redisCommand *cmd = sentinelcmds+j;
retval = dictAdd(server.commands, sdsnew(cmd->name), cmd);
serverAssert(retval == DICT_OK);
}
sentinel.current_epoch = 0;
//根據配置檔案,初始化自己需要監控的master(一個sentinel是可能監控多個 master的)
sentinel.masters = dictCreate(&instancesDictType,NULL);
sentinel.tilt = 0;
sentinel.tilt_start_time = 0;
sentinel.previous_time = mstime();
sentinel.running_scripts = 0;
sentinel.scripts_queue = listCreate();
sentinel.announce_ip = NULL;
sentinel.announce_port = 0;
sentinel.simfailure_flags = SENTINEL_SIMFAILURE_NONE;
sentinel.deny_scripts_reconfig = SENTINEL_DEFAULT_DENY_SCRIPTS_RECONFIG;
memset(sentinel.myid,0,sizeof(sentinel.myid));
}
initSentinel 主要的作用還是清空普通模式的 redis 命令表,載入獨屬於 sentinel 使用的命令,並初始化自己監控的 master 集合。
至此,sentinel 的初始化就算完成了,剩下的自動監控則在定時函式 serverCron 中,我們一起來看看。
//間隔 100 毫秒執行一次 sentinelTimer
run_with_period(100) {
if (server.sentinel_mode) sentinelTimer();
}
也就是說,sentinel 啟動之後,會間隔 100 毫秒在 serverCron 呼叫一次 sentinelTimer 函式處理一些重要事件(其實,sentinelTimer 中會修改執行間隔)。
void sentinelTimer(void) {
sentinelCheckTiltCondition();
sentinelHandleDictOfRedisInstances(sentinel.masters);
sentinelRunPendingScripts();
sentinelCollectTerminatedScripts();
sentinelKillTimedoutScripts();
server.hz = CONFIG_DEFAULT_HZ + rand() % CONFIG_DEFAULT_HZ;
}
sentinelTimer 函式體非常簡短,但不要高興太早。sentinelCheckTiltCondition 函式我們不去多說,redis 高度依賴系統時間,如果多次檢測到系統時鐘紀元不準確,它會判定當前系統不穩定,進入 TITL,類似一個休眠的狀態,不會為我們做故障轉移,僅僅收集資料,等待系統恢復穩定。
void sentinelHandleDictOfRedisInstances(dict *instances) {
dictIterator *di;
dictEntry *de;
sentinelRedisInstance *switch_to_promoted = NULL;
di = dictGetIterator(instances);
//遞迴遍歷監控的所有 master,執行監控操作
while((de = dictNext(di)) != NULL) {
sentinelRedisInstance *ri = dictGetVal(de);
//這是監控的核心邏輯,下文細說
sentinelHandleRedisInstance(ri);
if (ri->flags & SRI_MASTER) {
//不論是 slave 還是其他 sentinel,都視作一個redisInstance
sentinelHandleDictOfRedisInstances(ri->slaves);
sentinelHandleDictOfRedisInstances(ri->sentinels);
if (ri->failover_state == SENTINEL_FAILOVER_STATE_UPDATE_CONFIG) {
switch_to_promoted = ri;
}
}
}
if (switch_to_promoted)
sentinelFailoverSwitchToPromotedSlave(switch_to_promoted);
dictReleaseIterator(di);
}
sentinelHandleRedisInstance 主要兩個部分組成,監控和故障轉移。
void sentinelHandleRedisInstance(sentinelRedisInstance *ri) {
sentinelReconnectInstance(ri);
sentinelSendPeriodicCommands(ri);
if (sentinel.tilt) {
if (mstime()-sentinel.tilt_start_time < SENTINEL_TILT_PERIOD) return;
sentinel.tilt = 0;
sentinelEvent(LL_WARNING,"-tilt",NULL,"#tilt mode exited");
}
sentinelCheckSubjectivelyDown(ri);
if (ri->flags & (SRI_MASTER|SRI_SLAVE)) {
/* Nothing so far. */
}
if (ri->flags & SRI_MASTER) {
sentinelCheckObjectivelyDown(ri);
if (sentinelStartFailoverIfNeeded(ri))
sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_ASK_FORCED);
sentinelFailoverStateMachine(ri);
sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_NO_FLAGS);
}
}
sentinelReconnectInstance 函式做兩件事,因為當前是一個 sentinel 例項,所以第一件事就是與當前遍歷的 instance 建立連線,不論它是 master、slave 或是 sentinel,並在成功建立連線後傳送 ping 命令。第二,如果當前遍歷的是一個 master 或 slave,則會訂閱它的 sentinel_hello 頻道,當這個頻道上有訊息更新,則會廣播所有訂閱的該頻道的客戶端。(訂閱這個頻道的主要作用還是用於發現其他 sentinel 以及與其他 sentinel 交流自己對監控的節點的看法)
sentinelSendPeriodicCommands 函式預設每間隔十秒給 master 和 slave 傳送 info 命令,瞭解他們的主從關係,如果此 instance 被自己主觀下線了,那麼會加快傳送 info 命令的頻率,以保證自己最快知道主從關係變化,還會每間隔一秒 ping 所有型別的例項。
以上其實是 sentinelHandleRedisInstance 中監控節點的部分,下面我們繼續看其故障轉移怎麼做的。
void sentinelHandleRedisInstance(sentinelRedisInstance *ri) {
sentinelReconnectInstance(ri);
sentinelSendPeriodicCommands(ri);
//判斷是否需要進入 tilt 模式
if (sentinel.tilt) {
if (mstime()-sentinel.tilt_start_time < SENTINEL_TILT_PERIOD) return;
sentinel.tilt = 0;
sentinelEvent(LL_WARNING,"-tilt",NULL,"#tilt mode exited");
}
//判斷是否需要主觀下線該節點
sentinelCheckSubjectivelyDown(ri);
if (ri->flags & (SRI_MASTER|SRI_SLAVE)) {
/* Nothing so far. */
}
if (ri->flags & SRI_MASTER) {
//判斷是否需要客戶下線該節點
sentinelCheckObjectivelyDown(ri);
//如果確定該節點客觀下線,進行領導者選舉
if (sentinelStartFailoverIfNeeded(ri))
sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_ASK_FORCED);
//故障轉移
sentinelFailoverStateMachine(ri);
sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_NO_FLAGS);
}
}
sentinelCheckSubjectivelyDown 檢測當前節點是否需要主觀下線,判斷條件是此節點對於自己的配置,如果當前這個例項超過配置的時間段沒有回覆自己的 ping,那麼判斷它下線,設定主觀下線標誌位。
sentinelCheckObjectivelyDown 檢測當前是否達到客觀下線的條件,檢測邏輯是這樣的,遍歷所有的兄弟 sentinel 結構,看看他們有沒有把當前節點主觀下線,統計數量,如果達到 quorum,則判定該 master 客觀下線,設定標誌位並通過頻道通知到其他 兄弟 sentinel。
sentinelStartFailoverIfNeeded 判斷當前是否已有 sentinel 在進行故障轉移(通過 master 的一個標誌位,如果有 sentinel 正在進行故障轉移,這個標誌位會被設定),如果有,則自己不參與,什麼都不做。
sentinelAskMasterStateToOtherSentinels 會去給其他 sentinel 傳送訊息,要求它同意自己作為領導者對 master 進行故障轉移。具體怎麼做的呢,首先會拿到自己這邊關於所有兄弟 sentinel 的資訊進行一個遍歷,並給他們傳送命令 is-master-down-by-addr 要求他們同意自己成為領導者,並設定回撥函式 sentinelReceiveIsMasterDownReply 處理回覆。
如果某個 sentinel 收到別人發來的領導者投票,且自己沒有給其他人投過票的話就會同意,反之不予理睬。
當某個 sentinel 收到足夠的票數,則它認為自己就是 leader,標誌 master 為故障轉移中,並進行真正的故障轉移操作。
void sentinelFailoverStateMachine(sentinelRedisInstance *ri) {
serverAssert(ri->flags & SRI_MASTER);
if (!(ri->flags & SRI_FAILOVER_IN_PROGRESS)) return;
switch(ri->failover_state) {
//故障轉移開始
case SENTINEL_FAILOVER_STATE_WAIT_START:
sentinelFailoverWaitStart(ri);
break;
//選擇一個要晉升的從節點
case SENTINEL_FAILOVER_STATE_SELECT_SLAVE:
sentinelFailoverSelectSlave(ri);
break;
//傳送slaveof no one命令,使從節點變為主節點
case SENTINEL_FAILOVER_STATE_SEND_SLAVEOF_NOONE:
sentinelFailoverSendSlaveOfNoOne(ri);
break;
//等待被選擇的從節點晉升為主節點,如果超時則重新選擇晉升的從節點
case SENTINEL_FAILOVER_STATE_WAIT_PROMOTION:
sentinelFailoverWaitPromotion(ri);
break;
//給所有的從節點發送slaveof命令,同步新的主節點
case SENTINEL_FAILOVER_STATE_RECONF_SLAVES:
sentinelFailoverReconfNextSlave(ri);
break;
}
}
sentinelFailoverStateMachine 故障轉移包括五個步驟,分五個 sentinelTimer 執行週期處理。當新 master 選舉完成,會給其他兄弟 sentinel 廣播,告知他們新的 master 已經出現,他們收到後,會撤銷對原 master 的主觀下線,並重新開始監控新的 master。
至此,我們對 Sentinel 的介紹與原始碼分析就結束了,它本質上就是一個執行在特殊模式下的 redis-server,通過不斷 ping 主從節點,在感知他們可能出現故障之後,集體進行一個投票認定並選舉出一個人去執行 master 的客觀下線。
下一篇,我們看 redis 中更牛逼的 cluster。
相關推薦
Redis哨兵模式(sentinel)學習總結及部署記錄(主從複製、讀寫分離、主從切換)
Redis的叢集方案大致有三種:1)redis cluster叢集方案;2)master/slave主從方案;3)哨兵模式來進行主
Redis 哨兵模式(Sentinel)
上一篇我們介紹了 redis 主從節點之間的資料同步複製技術,通過一次全量複製和不間斷的命令傳播,可以達到主從節點資料同步備份的效果,一旦主節點宕機,我們可以選擇一個工作正常的 slave 成為新的主節點,並讓其他 slave 去同步它。 這是處理 redis 故障轉移的一個方式,但卻不具備生產實用性,因為畢
Redis全方位講解--哨兵模式(Sentinel模式)
前言 當按照上一篇《redis主從複製》部署好之後,我們會想,一旦redis的master出現了宕機,並且我們並沒有及時發現,這時候就可能會出現資料丟失或程式無法執行。此時,redis的哨兵模式就派上用場了,可以用它來做redis的高可用。 功能作用 監控(monitoring
Redis全方位講解--哨兵模式(Sentinel模式)(轉載)
重新 onf 一段時間 演示 ood 配置文件 宕機 退出 mage 前言 當按照上一篇《redis主從復制》部署好之後,我們會想,一旦redis的master出現了宕機,並且我們並沒有及時發現,這時候就可能會出現數據丟失或程序無法運行。此時,redis的哨兵模式就派
Redis的哨兵部署(sentinel)(實驗)
redis哨兵部署 redis哨兵搭建 redis哨兵使用 redis-sentinel部署 redis-sentinel詳解 首先感謝“吧喱公路”的引導,打開了我對哨兵的理解思路,再次謝謝。Redis的哨兵(sentinel) 哨兵適用於非集群結構的redis環境,比如:re
分散式Redis故障轉移(sentinel)
當2臺以上Redis例項形成了主備關係,他們組成的叢集就具備了一定的高可用:當master 故障時,slave可以成為新的master,對外提供讀寫服務,這種執行機制稱為failover。那麼誰去發現master的故障,並做failover呢? 一種方式
Redis哨兵(Sentinel)模式
主從切換技術的方法是:當主伺服器宕機後,需要手動把一臺從伺服器切換為主伺服器,這就需要人工干預,費事費力,還會造成一段時間內服務不可用。這不是一種推薦的方式,更多時候,我們優先考慮哨兵模式。 一、哨兵模式概述 哨兵模式是一種特殊的模式,首先Redis提供了哨兵的命令,哨兵是一個獨
Redis高可用叢集-哨兵模式(Redis-Sentinel)搭建配置教程【Windows環境】
No cross,no crown . 不經歷風雨,怎麼見彩虹。 Redis哨兵模式,用現在流行的話可以說就是一個“哨兵機器人”,給“哨兵機器人”進行相應的配置之後,這個”機器人”可以7*24小時工作,它能能夠自動幫助你做一些事情,如監控,提醒,自動處
基於哨兵(Sentinel)模式搭建Redis叢集搭建
這篇文章主要是想把自己搭建Redis哨兵模式叢集的過程記下來,方便後面搭建的重複性工作。 首先一點,學習任何知識都要學會看官網,所以,可以參考官網進行配置。我為了省事兒,參照了公司的規範來搭建的。官網地址:https://redis.io/ 有個官方下載地址,可以直接下載各
Redis哨兵(Sentinel)模式快速入門
更多內容,歡迎關注微信公眾號:全菜工程師小輝。公眾號回覆關鍵詞,領取免費學習資料。 當主伺服器宕機後,需要手動把一臺從伺服器切換為主伺服器,這就需要人工干預,費事費力,還會造成一段時間內服務不可用。 所以更多時候,我們優先考慮哨兵(sentinel) 模式。 Redis sentinel是Redis高可用實現
Redis詳解(九)------ 哨兵(Sentinel)模式詳解
在上一篇部落格----Redis詳解(八)------ 主從複製,我們簡單介紹了Redis的主從架構,但是這種主從架構存在一個問題,當主伺服器宕機,從伺服器不能夠自動切換成主伺服器,為了解決這個問題,我們又介紹了哨兵模式,本篇部落格我們繼續深入的介紹一下這種模式. 1、架構圖 &nb
Redis的哨兵(sentinel)(概念)
redis哨兵 redis-sentinel Redis的哨兵(sentinel) redis的sentinel系統用於管理多個redis服務器實例(instance)。 哨兵適用於非集群結構的redis環境,比如:redis主從環境。 在redis集群中,節點擔當了哨
分散式快取技術redis學習系列(六)——sentinel哨兵機制
一、簡介: 1、Redis 的 Sentinel 系統用於管理多個 Redis 伺服器(instance),該系統執行以下三個任務: 1)監控(Monitoring):Sentinel 會不斷地檢查你的主伺服器和從伺服器是否運作正常。 2)提醒(Notifica
Redis 哨兵模式的理論(轉載)
Sentinel是Redis的高可用性解決方案,本文主要介紹Sentinel的初始化過程及其與一般Redis伺服器的區別。並說明Sentinel監視伺服器的方法和原理,說明Sentinel如何判斷一個伺服器是否線上,並介紹故障轉移過程。 I、上帝視角看Sentinel
Redis 哨兵模式的原始碼(轉載)
建議閱讀: 1、Sentinel的理論部分見: I、上帝視角 1、Sentinel也是Redis伺服器,只是與普通伺服器職責不同,其負責監視Redis伺服器,以提高伺服器叢集的可靠性。Sentinel與普通伺服器共用一套框架(網路框架,底層資料結構,訂閱與釋出機制),但又
redis主從 + 哨兵(sentinel)+ VIP漂移實現高可用
1. 環境及ip角色說明: 這裡使用三臺伺服器,每臺伺服器上開啟一個redis-server和redis-sentinel服務, redis-server埠為8000,redis-sentinel的埠為6800,修改預設埠是安全的第一步 redis-server: 10.
redis的主從和哨兵模式(一主二從)
Redis的主從及哨兵模式的搭建(一主二從) 一.搭建主從模式 首先在linux中安裝好redis(這裡就不詳細介紹) 然後複製redis.conf複製出兩份(我們這裡用16379,26379作為從節點 cp redis.conf redis-16379.conf
採用 redis主從 + 哨兵(sentinel) + vip漂移搭建一套redis高可用叢集
一、單個例項 當系統中只有一臺redis執行時,一旦該redis掛了,會導致整個系統無法執行。 單個例項 二、備份 由於單臺redis出現單點故障,就會導致整個系統不可用,所以想到的辦法自然就是備份(一般工業界認為比較安全的備份數應該是3份)。當一臺redis出現問題了,另一臺
Spring Boot 入門(十):整合Redis哨兵模式,實現Mybatis二級快取
本片文章續《Spring Boot 入門(九):整合Quartz定時任務》。本文主要基於redis實現了mybatis二級快取。較redis快取,mybaits自帶快取存在缺點(自行谷歌)。本文是基於docker安裝redis主從模式。 1.redis安裝 (1)首先安裝redis叢集模式,建立redis目錄
Redis 哨兵高可用(Sentinel)
哨兵機制是 Redis 高可用中重要的一環,其核心是 **通過高可用哨兵叢集,監控主從複製的健康狀態,並實現自動災備**: 哨兵叢集以叢集的方式進行部署,這種分散式特性具有以下優點: - 避免系統中存在單點,防止災備機制失效 - 切換 master 必須經過多個 sentinel 節點協商同意,避