Redis Sentinel

[toc]
Sentinel是Redis的高可用解決方案稿饰,由一個(gè)或多個(gè)Sentinel實(shí)例組成的Sentinel系統(tǒng)可以監(jiān)視多個(gè)主服務(wù)器压汪,以及這些主服務(wù)器屬下的所有從服務(wù)器忧换,并在被監(jiān)視的主服務(wù)器下線時(shí)盔憨,自動(dòng)將下線主服務(wù)器屬下的某個(gè)從服務(wù)器升級(jí)為主服務(wù)器洗搂,代替下線的主服務(wù)器繼續(xù)處理命令請(qǐng)求。若已下線的主服務(wù)器重新上線沛申,則將它設(shè)置為新的主服務(wù)器的從服務(wù)器劣领。

啟動(dòng)并初始化一個(gè)Sentinel

  1. 啟動(dòng)命令
    $ redis-sentinel /path/to/your/sentinel.conf
或  $ redis-server /path/to/your/sentinel.conf --sentinel
  1. 初始化服務(wù)器
    Sentinel本質(zhì)上是一個(gè)運(yùn)行在特殊模式下的Redis服務(wù)器,不過(guò)功能不一樣:

    image

  2. Sentinel專用代碼
    Sentinel模式下的Redis服務(wù)器使用專用的代碼铁材,只支持PING尖淘、SENTINEL、INFO衫贬、SUBSCRIBE德澈、UNSUBSCRIBE歇攻、PSUBSCRIBE固惯、PUNSUBSCRIBE七個(gè)命令:

// 服務(wù)器在 sentinel 模式下可執(zhí)行的命令
struct redisCommand sentinelcmds[] = {
    {"ping",pingCommand,1,"",0,NULL,0,0,0,0,0},
    {"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0},
    {"subscribe",subscribeCommand,-2,"",0,NULL,0,0,0,0,0},
    {"unsubscribe",unsubscribeCommand,-1,"",0,NULL,0,0,0,0,0},
    {"psubscribe",psubscribeCommand,-2,"",0,NULL,0,0,0,0,0},
    {"punsubscribe",punsubscribeCommand,-1,"",0,NULL,0,0,0,0,0},
    {"publish",sentinelPublishCommand,3,"",0,NULL,0,0,0,0,0},
    {"info",sentinelInfoCommand,-1,"",0,NULL,0,0,0,0,0},
    {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0}
};
  1. Sentinel狀態(tài)
    服務(wù)器會(huì)初始化sentinelState結(jié)構(gòu),其中的字典masters記錄了該sentinel監(jiān)視的主服務(wù)器相關(guān)信息缴守,字典的鍵是主服務(wù)器的名字葬毫,值是一個(gè)sentinelRedisInstance結(jié)構(gòu),包含很多屬性屡穗,其中sentinelAddr是一個(gè)保存IP地址和端口號(hào)的結(jié)構(gòu)贴捡。
/* Sentinel 的狀態(tài)結(jié)構(gòu) */
struct sentinelState {
    uint64_t current_epoch;   // 當(dāng)前紀(jì)元
    dict *masters; 
    // 保存了所有被這個(gè) sentinel 監(jiān)視的主服務(wù)器
    // 字典的鍵是主服務(wù)器的名字
    // 字典的值則是一個(gè)指向 sentinelRedisInstance 結(jié)構(gòu)的指針

    ... ...
} sentinel;

// Sentinel 會(huì)為每個(gè)被監(jiān)視的 Redis 實(shí)例創(chuàng)建相應(yīng)的 sentinelRedisInstance 實(shí)例
// (被監(jiān)視的實(shí)例可以是主服務(wù)器、從服務(wù)器村砂、或者其他 Sentinel )
typedef struct sentinelRedisInstance {
    int flags;    // 標(biāo)識(shí)值烂斋,記錄了實(shí)例的類(lèi)型,以及該實(shí)例的當(dāng)前狀態(tài)
    char *name;   
    // 實(shí)例的名字
    // 主服務(wù)器的名字由用戶在配置文件中設(shè)置
    // 從服務(wù)器以及 Sentinel 的名字由 Sentinel 自動(dòng)設(shè)置
    // 格式為 ip:port 础废,例如 "127.0.0.1:26379"
    char *runid;    // 實(shí)例的運(yùn)行 ID
    sentinelAddr *addr;   // 實(shí)例的地址
    dict *sentinels;   // 其他同樣監(jiān)控這個(gè)主服務(wù)器的所有 sentinel
    dict *slaves;  
    // 如果這個(gè)實(shí)例代表的是一個(gè)主服務(wù)器
    // 那么這個(gè)字典保存著主服務(wù)器屬下的從服務(wù)器
    // 字典的鍵是從服務(wù)器的名字汛骂,字典的值是從服務(wù)器對(duì)應(yīng)的 sentinelRedisInstance 結(jié)構(gòu)
    ... ...
} sentinelRedisInstance;

/* 地址對(duì)象,用于保存 IP 地址和端口 */
typedef struct sentinelAddr {
    char *ip;
    int port;
} sentinelAddr;

假設(shè)一個(gè)sentinel監(jiān)聽(tīng)兩個(gè)主服務(wù)器评腺,結(jié)果是:


image
image
  1. 創(chuàng)建連接主服務(wù)器的網(wǎng)絡(luò)連接
    對(duì)于每個(gè)主服務(wù)器帘瞭,Sentinel創(chuàng)建兩個(gè)連接主服務(wù)器的異步網(wǎng)絡(luò)連接:
  • 命令連接,用于向主服務(wù)器發(fā)送命令并接收命令回復(fù)蒿讥;
  • 訂閱連接蝶念,用于訂閱主服務(wù)器的 sentinel:hello頻道抛腕。
  1. 獲取主服務(wù)器信息
    Sentinel默認(rèn)每10秒向監(jiān)視的主服務(wù)器發(fā)送INFO命令:得到主服務(wù)器以及其下屬?gòu)姆?wù)器的信息:
    image

根據(jù)返回的信息可以更新或創(chuàng)建sentinelRedisInstance實(shí)例結(jié)構(gòu)中的信息,并創(chuàng)建連接到從服務(wù)器的命令連接和訂閱連接:


image
  1. 獲取從服務(wù)器信息
    Sentinel每10s向從服務(wù)器發(fā)送INFO命令媒殉,獲得從服務(wù)器運(yùn)行ID担敌、角色、其主服務(wù)器IP地址和端口适袜、連接狀態(tài)柄错、優(yōu)先級(jí)、復(fù)制偏移量等信息苦酱,更新從服務(wù)器的實(shí)力結(jié)構(gòu):

    image

  2. 頻道信息
    Sentinel每2s會(huì)通過(guò)命令連接向所有監(jiān)視的主服務(wù)器和從服務(wù)器發(fā)送命令:

PUBLISH __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"

該命令向服務(wù)器的sentinel:hello頻道發(fā)送一條信息售貌,其他訂閱該頻道的Sentinel會(huì)通過(guò)該頻道接收到消息:

image

如果Sentinel收到的信息是自己發(fā)送的,則忽略疫萤;否則根據(jù)信息更新實(shí)例結(jié)構(gòu)中的sentinels字典:


image

這樣就能發(fā)現(xiàn)監(jiān)視同一個(gè)主服務(wù)器的其他Sentinel了颂跨,并與其他Sentinel建立命令連接,形成網(wǎng)絡(luò)扯饶。

下線

Sentienl默認(rèn)每秒向創(chuàng)建了命令連接的實(shí)例(包括主服務(wù)器恒削、從服務(wù)器和其他Sentinel)發(fā)送PING命令,并通過(guò)實(shí)例返回的PING命令回復(fù)來(lái)判斷實(shí)例是否在線尾序。

  • 若回復(fù)是+PING钓丰、-LOADING、-MASTERDOWN每币,則有效携丁;
  • 否則就是無(wú)效回復(fù)。

若連續(xù)一段時(shí)間(down_after_milliseconds)內(nèi)返回的是無(wú)效回復(fù)兰怠,則將Sentinel狀態(tài)中的對(duì)應(yīng)實(shí)例結(jié)構(gòu)的flags屬性設(shè)置為主觀下線(SRI_S_DOWN)梦鉴。

不同Sentinel對(duì)down_after_milliseconds設(shè)置可能不同,因此不同Setinel對(duì)某個(gè)服務(wù)器是否主觀下線的判斷可能不同揭保。

當(dāng)Sentinel判斷一個(gè)主服務(wù)器為主觀下線后肥橙,會(huì)詢問(wèn)其他Sentinel該主服務(wù)器的狀態(tài),若超過(guò)一定數(shù)量的Sentinel判斷其為主觀下線秸侣,則將該主服務(wù)器判定為客觀下線存筏,并對(duì)其執(zhí)行故障轉(zhuǎn)移操作。

  1. 詢問(wèn)
    發(fā)送以下命令進(jìn)行詢問(wèn):
SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <runid>
image
  1. 目標(biāo)Sentinel接收詢問(wèn)命令
    目標(biāo)Sentinel接收到詢問(wèn)命令味榛,則根據(jù)詢問(wèn)命令的IP和端口號(hào)椭坚,檢查對(duì)應(yīng)主服務(wù)器的狀態(tài),然后回復(fù):
  • <down_state>
  • <leader_runid>
  • <leader_epoch>


    image
  1. 接收詢問(wèn)命令回復(fù)
    統(tǒng)計(jì)同意主服務(wù)器已下線的Sentinel數(shù)量励负,若超過(guò)某個(gè)數(shù)值藕溅,則則判定該主服務(wù)器為客觀下線(SRI_O_DOWN)。
    不同Sentinel判斷客觀下線的條件(數(shù)量值)可能不同继榆。

選舉領(lǐng)頭Sentinel

當(dāng)一個(gè)主服務(wù)器被判定為客觀下線時(shí)巾表,監(jiān)視這個(gè)主服務(wù)器的Sentienl會(huì)協(xié)商出一個(gè)領(lǐng)頭Sentinel汁掠,并由領(lǐng)頭Sentinel對(duì)下線主服務(wù)器進(jìn)行故障轉(zhuǎn)移操作。

領(lǐng)頭Sentinel選舉規(guī)則和方法:

  • 所有在線的Sentinel都有被選為領(lǐng)頭Sentinel的資格集币,換句話說(shuō)考阱,監(jiān)視同一個(gè)主服 務(wù)器的多個(gè)在線Sentinel中的任意一個(gè)都有可能成為領(lǐng)頭Sentinel。
  • 每次進(jìn)行領(lǐng)頭Sentinel選舉之后鞠苟,不論選舉是否成功乞榨,所有Sentinel的配置紀(jì)元(configuration epoch)的值都會(huì)自增一次。配置紀(jì)元實(shí)際上就是一個(gè)計(jì)數(shù)器当娱,并沒(méi)有什么特別的吃既。
  • 在一個(gè)配置紀(jì)元里面,所有Sentinel都有一次將某個(gè)Sentinel設(shè)置為局部領(lǐng)頭 Sentinel的機(jī)會(huì)跨细,并且局部領(lǐng)頭一旦設(shè)置鹦倚,在這個(gè)配置紀(jì)元里面就不能再更改。 每個(gè)發(fā)現(xiàn)主服務(wù)器進(jìn)人客現(xiàn)下線的Sentinel都會(huì)要求其他Sentinel將自己設(shè)置為局部領(lǐng)頭Sentinel冀惭。
  • 當(dāng)一個(gè)Sentinel(源Sentinel)向另一個(gè) Sentinel (目標(biāo)Sentinel)發(fā)送SENTINEL is-master-down-by-addr命令震叙,并且命令中的runid參數(shù)不是*符號(hào)而是源Sentinel的運(yùn)行ID時(shí),這表示源Sentinel要求目標(biāo)Sentinel將前者設(shè)置為后者的局 部 領(lǐng) 頭 Sentinel散休。
  • Sentinel設(shè)置局部領(lǐng)頭Sentinel的規(guī)則是先到先得:最先向目標(biāo)Sentinel發(fā)送設(shè)置要求的源Sentinel將成為目標(biāo)Sentinel的局部領(lǐng)頭Sentinel,而之后接收到的所有設(shè)置 要求都會(huì)被目標(biāo)Sentinel拒絕媒楼。
  • 目標(biāo)Sentinel在接收到SENTINEL is-master-down-by-addr命令之后,將向 源Sentinel返回一條命令回復(fù)戚丸,回復(fù)中的leader_runid參數(shù)和leader_epoch 參數(shù)分別記錄了目標(biāo)Sentinel的局部領(lǐng)頭Sentinel運(yùn)行ID和配置紀(jì)元划址。
  • 源Sentinel在接收到目標(biāo)Sentinel返回的命令回復(fù)之后,會(huì)檢查回復(fù)中l(wèi)eadeir_ epoch參敗的值和自己的配置紀(jì)元是否相同昏滴,如果相同的話猴鲫,那么源Sentinel繼續(xù)取出回復(fù)中的leader_runid參數(shù)对人,如果leader_runid參數(shù)的值和源Sentinel的運(yùn)行ID 一致谣殊,那么表示目標(biāo)Sentinel將源Sentine設(shè)置成了局部領(lǐng)頭Sentinel。
  • 如果有某個(gè)Sentinel被半數(shù)以上的Sentinel設(shè)置成了局部領(lǐng)頭Sentinel, 那 么 這 個(gè)Sentinel成為領(lǐng)頭Sentinel牺弄。舉個(gè)例子姻几,在一個(gè)由10個(gè)Sentinel組成的Sentinel系統(tǒng)里面,只要有大于等于10/2+1=6個(gè)Sentinel將某個(gè)Sentinel設(shè)置為局部領(lǐng)頭Sentinel,那么被設(shè)置的某個(gè)Sentinel就會(huì)成為領(lǐng)頭Sentinel势告。
  • 因?yàn)轭I(lǐng)頭Sentinel的產(chǎn)生需要半數(shù)以上Sentinel的支持蛇捌,并且每個(gè)Sentinel在每個(gè) 配置紀(jì)元里面只能設(shè)置一次局部領(lǐng)頭Sentinel,所以在一個(gè)配置紀(jì)元里面,只會(huì)出現(xiàn) 一個(gè)領(lǐng)頭 Sentinel咱台。
  • 如果在給定時(shí)限內(nèi)络拌,沒(méi)有一個(gè)Sentinel被選舉為領(lǐng)頭Sentinel, 那么各個(gè)Sentinel將在一段時(shí)間之后再次進(jìn)行選舉,直到選出領(lǐng)頭Sentinel為止回溺。

故障轉(zhuǎn)移

領(lǐng)頭Sentinel將對(duì)已下線的主服務(wù)器執(zhí)行故障轉(zhuǎn)移操作春贸,執(zhí)行以下三個(gè)步驟:

  1. 在已下線主服務(wù)器屬下的所有從服務(wù)器里邊混萝,挑選一個(gè)從服務(wù)器,并將其轉(zhuǎn)換為主服務(wù)器萍恕;
  2. 讓已下線主服務(wù)器屬下的所有從服務(wù)器改為復(fù)制新的主服務(wù)器逸嘀;
  3. 將已下線主服務(wù)器設(shè)置為新的主服務(wù)器的從服務(wù)器,當(dāng)這個(gè)舊的主服務(wù)器重新上線允粤,就會(huì)成為新的主服務(wù)器的從服務(wù)器崭倘。

挑選新的主服務(wù)器規(guī)則:
領(lǐng)頭Sentinel會(huì)將己下線主服務(wù)器的所有從服務(wù)器保存到一個(gè)列表里面,然后按以下規(guī)則类垫,一項(xiàng)一項(xiàng)地對(duì)列表進(jìn)行過(guò)濾:

  1. 刪除列表中所有處于下線或者斷線狀態(tài)的從服務(wù)器司光,這可以保證列表中剩余的從服務(wù)器都是正常在線的;
  2. 刪除列表中所有最近五秒內(nèi)沒(méi)有回復(fù)過(guò)領(lǐng)頭Sentinel的INFO命令的從服務(wù)器悉患,這可以保證列表中剩余的從服務(wù)器都是最近成功進(jìn)行過(guò)通信的飘庄。
  3. 刪除所有與已下線主服務(wù)器連接斷開(kāi)建過(guò)down-after-milliseconds10毫秒的從服務(wù)器 : down- after-milliseconds選項(xiàng)指定了判斷主服務(wù)器下線所需的時(shí)間,而刪除斷開(kāi)時(shí)長(zhǎng)超過(guò)down-after-milliseconds10毫秒的從服務(wù)器购撼, 則可以保證列表中剩余的從服務(wù)器保存的數(shù)據(jù)都是比較新的跪削。

之后,領(lǐng)頭Sentinel將根據(jù)從服務(wù)器的優(yōu)先級(jí)迂求,對(duì)列表中剩余的從服務(wù)器進(jìn)行排序碾盐,并選出其中優(yōu)先級(jí)最高的從服務(wù)器。
如 果 有 多 個(gè) 具 有 相 同 最 高 優(yōu) 先級(jí) 的 從服務(wù)器揩局,那么領(lǐng)頭Sentinel將按從服務(wù)器的復(fù)制偏移量毫玖,對(duì)具有相同最高優(yōu)先級(jí)的所有從服務(wù)器進(jìn)行排序,并選出其中偏移量最大的從服務(wù)器 (復(fù)制偏移量最大的從服務(wù)器就是保存著最新數(shù)據(jù)的從服務(wù)器)凌盯。

最后付枫,如果有多個(gè)優(yōu)先級(jí)最高箱蝠、復(fù)制偏移量最大的從服務(wù)器蟆盹,那么領(lǐng)頭Sentinel將按照運(yùn)行ID對(duì)這些從服務(wù)器進(jìn)行排序,并選出其中運(yùn)行ID最小的從服務(wù)器匿刮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末县忌,一起剝皮案震驚了整個(gè)濱河市掂榔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌症杏,老刑警劉巖装获,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異厉颤,居然都是意外死亡穴豫,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)逼友,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)精肃,“玉大人潘鲫,你說(shuō)我怎么就攤上這事±哒龋” “怎么了溉仑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)状植。 經(jīng)常有香客問(wèn)我浊竟,道長(zhǎng),這世上最難降的妖魔是什么津畸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任振定,我火速辦了婚禮,結(jié)果婚禮上肉拓,老公的妹妹穿的比我還像新娘后频。我一直安慰自己,他們只是感情好暖途,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布卑惜。 她就那樣靜靜地躺著,像睡著了一般驻售。 火紅的嫁衣襯著肌膚如雪露久。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,578評(píng)論 1 305
  • 那天欺栗,我揣著相機(jī)與錄音毫痕,去河邊找鬼。 笑死迟几,一個(gè)胖子當(dāng)著我的面吹牛消请,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播类腮,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼臊泰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了存哲?” 一聲冷哼從身側(cè)響起因宇,我...
    開(kāi)封第一講書(shū)人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤七婴,失蹤者是張志新(化名)和其女友劉穎祟偷,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體打厘,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡修肠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了户盯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌施。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饲化,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吗伤,到底是詐尸還是另有隱情吃靠,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布足淆,位于F島的核電站巢块,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏巧号。R本人自食惡果不足惜族奢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望丹鸿。 院中可真熱鬧越走,春花似錦、人聲如沸靠欢。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)门怪。三九已至庭敦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薪缆,已是汗流浹背秧廉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拣帽,地道東北人疼电。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像减拭,于是被迫代替她去往敵國(guó)和親蔽豺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容