鍍金池/ 教程/ 大數(shù)據(jù)/ 高可用(上)
使用 Redis 實(shí)現(xiàn) Twitter(上)
集群(下)
使用 Redis 實(shí)現(xiàn) Twitter(下)
使用 Redis 作為 LRU 緩存
高可用(上)
高可用客戶(hù)端指引
集群(中)
高可用(下)
持久化
Redis 介紹
集中插入
集群(上)
從入門(mén)到精通(上)
從入門(mén)到精通(下)
從入門(mén)到精通(中)
分片
數(shù)據(jù)類(lèi)型初探
復(fù)制

高可用(上)

Redis Sentinel 是 Redis 的官方高可用解決方案,是設(shè)計(jì)用來(lái)幫助管理 Redis 實(shí)例的系統(tǒng)。用于完成下面 4 個(gè)任務(wù):

  • 監(jiān)控(Monitoring)。Sentinel 不斷檢查你的主從實(shí)例是否運(yùn)轉(zhuǎn)正常。
  • 通知(Notification)。Sentinel 可以通過(guò) API 來(lái)通知系統(tǒng)管理員,或者其他計(jì)算機(jī)程序,被監(jiān)控的 Redis 實(shí)例出了問(wèn)題。
  • 自動(dòng)故障轉(zhuǎn)移(Automatic failover)。如果一臺(tái)主服務(wù)器運(yùn)行不正常,Sentinel 會(huì)開(kāi)始一個(gè)故障轉(zhuǎn)移過(guò)程,將從服務(wù)器提升為主服務(wù)器,配置其他的從服務(wù)器使用新的主服務(wù)器,使用 Redis 服務(wù)器的應(yīng)用程序在連接時(shí)會(huì)收到新的服務(wù)器地址通知。
  • 配置提供者(Configuration provider)。Sentinel 充當(dāng)客戶(hù)端服務(wù)發(fā)現(xiàn)的權(quán)威來(lái)源:客戶(hù)端連接到 Sentinel 來(lái)詢(xún)問(wèn)某個(gè)服務(wù)的當(dāng)前 Redis 主服務(wù)器的地址。當(dāng)故障轉(zhuǎn)移發(fā)生時(shí),Sentinel 會(huì)報(bào)告新地址。

分布式特性(Distributed nature)

Redis Sentinel 是一個(gè)分布式系統(tǒng),這意味著,你通常想要在你的基礎(chǔ)設(shè)施中運(yùn)行多個(gè) Sentinel 進(jìn)程,這些進(jìn)程使用 gossip 協(xié)議來(lái)判斷一臺(tái)主服務(wù)器是否下線(down),使用 agreement 協(xié)議來(lái)獲得授權(quán)以執(zhí)行故障轉(zhuǎn)移,并更新相關(guān)配置。

分布式系統(tǒng)具有特定的安全(safety)和活性(liveness)的問(wèn)題,為了更好地使用 Redis Sentinel,你應(yīng)該去理解 Sentinel 是如何作為一個(gè)分布式系統(tǒng)運(yùn)轉(zhuǎn)的,至少在較高的層面上。這會(huì)讓 Sentinel 變得更復(fù)雜,但是比單進(jìn)程系統(tǒng)更好,例如:

  • Sentinel 集群能對(duì)主服務(wù)器故障轉(zhuǎn)移,即使部分 Sentinel 失敗。
  • 單個(gè) Sentinel 工作不正常,或者連接不正常,在沒(méi)有別的 Sentinel 授權(quán)的情況下不能故障轉(zhuǎn)移主服務(wù)器。
  • 客戶(hù)端可以隨機(jī)連接到任何一個(gè) Sentinel 來(lái)獲取主服務(wù)器的配置信息。

獲取 Sentinel(Obtaining Sentinel)

當(dāng)前版本的 Sentinel 被稱(chēng)為 Sentinel 2。使用了更強(qiáng)大和簡(jiǎn)單的算法來(lái)重寫(xiě)最初的 Sentinel 實(shí)現(xiàn) (本文后面會(huì)解釋)。

穩(wěn)定版本的 Redis Sentinel 被打包在 Redis 2.8 中,這是最新的 Redis 版本。

新的開(kāi)發(fā)在不穩(wěn)定的分支中進(jìn)行,新的特性一旦穩(wěn)定了就會(huì)合并回 2.8 分支。

重要:即使你使用的是 Redis 2.6,你也應(yīng)該使用 Redis 2.8 自帶的 Sentinel。Redis 2.6 自帶的 Sentinel,也就是 Sentinel 1,已經(jīng)不贊成使用,并且有很多的 bug??傊銘?yīng)該盡快把你的 Redis 和 Sentinel 實(shí)例都遷移到 Redis 2.8,以獲得更好的全面體驗(yàn)。

運(yùn)行 Sentinel(Running Sentinel)

如果你使用 redis-sentinel 可執(zhí)行文件 (或者如果你有一個(gè)叫這個(gè)名字的到 redis-server 的符號(hào)鏈接),你可以使用下面的命令行來(lái)運(yùn)行 Sentinel:

redis-sentinel  /path/to/sentinel.conf  

另外,你可以直接使用 redis-server 可執(zhí)行文件并作為 Sentinel 模式啟動(dòng):

redis-server  /path/to/sentinel.conf  --sentinel  

兩種方式是一樣的。

但是,運(yùn)行 Sentinel 強(qiáng)制使用配置文件,這個(gè)文件被系統(tǒng)用來(lái)保存當(dāng)前狀態(tài),在重啟時(shí)能重新加載。如果沒(méi)有指定配置文件,或者配置文件的路徑不可寫(xiě),Sentinel 將拒絕啟動(dòng)。

Sentinel 運(yùn)行時(shí)默認(rèn)監(jiān)聽(tīng) TCP 端口 26379,所以為了讓 Sentinel 正常運(yùn)行,你的服務(wù)器必須開(kāi)放 26379 端口,以接受從其他 Sentinel 實(shí)例 IP 地址的連接。否則,Sentinel 間就沒(méi)法通信,沒(méi)法協(xié)調(diào),也不會(huì)執(zhí)行故障轉(zhuǎn)移。

配置 Sentinel(Configuring Sentinel)

Redis 的源碼發(fā)行版中包含一個(gè)叫做 sentinel.conf 的自說(shuō)明示例配置文件,可以用來(lái)配置 Sentinel,一個(gè)典型的最小配置文件看起來(lái)就像下面這樣:

sentinel  monitor  mymaster  127.0.0.1  6379  2  
sentinel  down-after-milliseconds  mymaster  60000  
sentinel  failover-timeout  mymaster  180000  
sentinel  parallel-syncs  mymaster  1  

sentinel  monitor  resque  192.168.1.3  6380  4  
sentinel  down-after-milliseconds  resque  10000  
sentinel  failover-timeout  resque  180000  
sentinel  parallel-syncs  resque  5  

你只需要指定你要監(jiān)控的主服務(wù)器,并給每一個(gè)主服務(wù)器(可以擁有任意多個(gè)從服務(wù)器)一個(gè)不同的名字。沒(méi)有必要指定從服務(wù)器,因?yàn)樗鼈儠?huì)被自動(dòng)發(fā)現(xiàn)。Sentinel 會(huì)根據(jù)從服務(wù)器的額外信息來(lái)自動(dòng)更新配置(為了在重啟時(shí)還能保留配置)。每次故障轉(zhuǎn)移時(shí)將一臺(tái)從服務(wù)器提升為主服務(wù)器時(shí)都會(huì)重寫(xiě)配置文件。

上面的示例配置監(jiān)控了兩個(gè) Redis 實(shí)例集合,每個(gè)由一個(gè)主服務(wù)器和未知數(shù)量的從服務(wù)器組成。其中一個(gè)實(shí)例集合叫做 mymaster,另一個(gè)叫做 resque。

為了說(shuō)得再清楚一點(diǎn),我們一行一行地來(lái)看看這些配置選項(xiàng)是什么意思:

第一行告訴 Redis 監(jiān)控一個(gè)叫做 mymaster 的主服務(wù)器,地址為 127.0.0.1,端口為 6379,判斷這臺(tái)主服務(wù)器失效需要 2 個(gè) Sentinel 同意(如果同意數(shù)沒(méi)有達(dá)到,自動(dòng)故障轉(zhuǎn)移則不會(huì)開(kāi)始)。

但是要注意,無(wú)論你指定多少個(gè)同意來(lái)檢測(cè)實(shí)例是否正常工作,Sentinel 需要系統(tǒng)中已知的大多數(shù) Sentinel 的投票才能開(kāi)始故障轉(zhuǎn)移,并且在故障轉(zhuǎn)移之后獲取一個(gè)新的配置紀(jì)元(configuration Epoch) 賦予新的配置。

在例子中,仲裁人數(shù) (quorum) 被設(shè)置為 2,所以使用 2 個(gè) Sentinel 同意某臺(tái)主服務(wù)器不可到達(dá)或者在一個(gè)錯(cuò)誤的情況中,來(lái)觸發(fā)故障轉(zhuǎn)移(但是,你后面還會(huì)看到,觸發(fā)一個(gè)故障轉(zhuǎn)移還不足以開(kāi)始一次成功的故障轉(zhuǎn)移,還需要授權(quán))。

其他的選項(xiàng)基本上都是這樣的形式:

sentinel  <option_name>  <master_name>  <option_value>  

它們的作用如下:

down-after-milliseconds 表示要使 Sentinel 開(kāi)始認(rèn)為實(shí)例已下線(down),實(shí)例不可到達(dá)(沒(méi)有響應(yīng)我們的 PING,或者響應(yīng)一個(gè)錯(cuò)誤) 的毫秒數(shù)。這個(gè)時(shí)間過(guò)后,Sentinel 將標(biāo)記實(shí)例為主觀下線(subjectively down,也稱(chēng) SDOWN),這還不足以開(kāi)啟自動(dòng)故障轉(zhuǎn)移。但是,如果足夠的實(shí)例認(rèn)為具備主觀下線條件,實(shí)例就會(huì)被標(biāo)記為客觀下線(objectively down)。需要同意的 Sentinel 數(shù)量依賴(lài)于為這臺(tái)主服務(wù)器的配置。

parallel-syncs 設(shè)置在一次故障轉(zhuǎn)移之后,被配置為同時(shí)使用新主服務(wù)器的從服務(wù)器數(shù)量。這個(gè)數(shù)字越小,完成故障轉(zhuǎn)移過(guò)程需要的時(shí)間就越多,如果從服務(wù)器配置為服務(wù)舊數(shù)據(jù),你可能不太希望所有的從服務(wù)器同時(shí)從新的主服務(wù)器重同步,盡管復(fù)制過(guò)程通常不會(huì)阻塞從服務(wù)器,但是在重同步過(guò)程中仍然會(huì)有一段停下來(lái)的時(shí)間來(lái)加載來(lái)自于主服務(wù)器的大量數(shù)據(jù)。設(shè)置這個(gè)選項(xiàng)的值為 1 可以確保每次只有一個(gè)從服務(wù)器不可用。

其他的選項(xiàng)將在本文的剩余篇幅里介紹,Redis 發(fā)行版本中自帶的示例 sentinel.conf 文件中也有詳細(xì)的文檔。

所有的配置參數(shù)可以在運(yùn)行時(shí)用 SENTINEL SET 命令修改。請(qǐng)看下文中運(yùn)行時(shí)重新配置 Sentinel 這一部分獲取更多的信息。

仲裁人數(shù)(Quorum)

本文前面的部分展示了每一個(gè)被 Sentinel 監(jiān)控的主服務(wù)器都關(guān)聯(lián)了一個(gè)仲裁人數(shù)的配置。它指定了同意主服務(wù)器不可達(dá)或者錯(cuò)誤條件需要的 Sentinel 進(jìn)程數(shù),以觸發(fā)一次故障轉(zhuǎn)移。

但是,故障轉(zhuǎn)移被觸發(fā)后,為了讓故障轉(zhuǎn)移真正執(zhí)行,必須至少大多數(shù)的 Sentinel 授權(quán)某個(gè) Sentinel 才能錯(cuò)誤轉(zhuǎn)移。

讓我們解釋的再清楚一些:

  • 仲裁人數(shù):檢測(cè)錯(cuò)誤條件以標(biāo)記主服務(wù)器為 ODOWN 所需要的 Sentinel 進(jìn)程數(shù)。
  • 故障轉(zhuǎn)移由 ODOWN 狀態(tài)觸發(fā)。
  • 一旦故障轉(zhuǎn)移被觸發(fā),故障轉(zhuǎn)移的 Sentinel 需要向大多數(shù) Sentinel 請(qǐng)求授權(quán)(或者大于大多數(shù),如果仲裁人數(shù)設(shè)置為大于大多數(shù)的話)。

差別看起來(lái)很微妙,但是實(shí)際上理解和使用起來(lái)都相當(dāng)簡(jiǎn)單。例如,如果你有 5 個(gè) Sentinel 實(shí)例,然后設(shè)置仲裁人數(shù)為 2,只要有 2 個(gè) Sentinel 認(rèn)為主服務(wù)器不可達(dá)就會(huì)觸發(fā)一次故障轉(zhuǎn)移,這兩個(gè) Sentinel 僅當(dāng)?shù)玫街辽?3 個(gè) Sentinel 的授權(quán)時(shí)才能故障轉(zhuǎn)移。

如果設(shè)置仲裁人數(shù)為 5,所有的 Sentinel 都必須同意主服務(wù)器的錯(cuò)誤條件,故障轉(zhuǎn)移需要所有 Sentinel 的授權(quán)。

配置紀(jì)元 (Configuration epochs)

Sentinel 需要大多數(shù)的授權(quán)來(lái)開(kāi)啟故障轉(zhuǎn)移是有幾個(gè)重要原因的:

當(dāng)一個(gè) Sentinel 得到授權(quán)了,就會(huì)為故障轉(zhuǎn)移的主服務(wù)器獲得一個(gè)唯一的配置紀(jì)元。這是在故障轉(zhuǎn)移完成后用于標(biāo)記新的配置的一個(gè)版本數(shù)字。因?yàn)榇蠖鄶?shù)同意將一個(gè)指定的版本賦予一個(gè)指定的 Sentinel,所以其它的 Sentinel 不能使用它。這意味著,每一次故障轉(zhuǎn)移的配置都使用一個(gè)唯一的版本來(lái)標(biāo)記。我們會(huì)看到為什么這個(gè)是如此的重要。

另外,Sentinel 有一個(gè)規(guī)則:如果一個(gè) Sentinel 為了指定的主服務(wù)器故障轉(zhuǎn)移而投票給另一個(gè) Sentinel,將會(huì)等待一段時(shí)間后試圖再次故障轉(zhuǎn)移這臺(tái)主服務(wù)器。這個(gè)延時(shí)(delay)是 failover-timeout,你可以在 sentinel.conf 中配置。這意味著,Sentinel 不會(huì)同時(shí)故障轉(zhuǎn)移同一臺(tái)主服務(wù)器,第一個(gè)請(qǐng)求被授權(quán)的將會(huì)嘗試,如果失敗了,過(guò)一會(huì)后另一個(gè)將會(huì)嘗試,等等。

Redis Sentinel 保證活性(liveness)屬性,如果大多數(shù) Sentinel 能夠?qū)υ?,如果主服?wù)器下線,最后只會(huì)有一個(gè)被授權(quán)來(lái)故障轉(zhuǎn)移。

Redis Sentinel 也保證安全(safety)屬性,每個(gè) Sentinel 將會(huì)使用不同的配置紀(jì)元來(lái)故障轉(zhuǎn)移同一臺(tái)主服務(wù)器。

配置傳播(Configuration propagation)

一旦一個(gè) Sentinel 能夠成功故障轉(zhuǎn)移一臺(tái)主服務(wù)器,會(huì)開(kāi)始廣播新的配置,從而使其他 Sentinel 更新關(guān)于這臺(tái)主服務(wù)器的信息。

為了認(rèn)定故障轉(zhuǎn)移是成功的,需要 Sentinel 能發(fā)送 SLAVEOF NO ONE 給選定的從服務(wù)器,并將其切換為主服務(wù)器,稍后可以在主服務(wù)器的 INFO 輸出中觀察到。

這時(shí),即使從服務(wù)器的重新配置還在進(jìn)行中,故障轉(zhuǎn)移被認(rèn)為是成功的,所有的 Sentinel 被要求開(kāi)始報(bào)告新的配置。

新配置傳播的方式,就是為什么我們需要每次 Sentinel 故障轉(zhuǎn)移時(shí)被授權(quán)一個(gè)不同的版本號(hào)(配置紀(jì)元)的原因。

每一個(gè) Sentinel 使用 Redis 的發(fā)布訂閱(Pub/Sub)消息不斷地廣播主服務(wù)器的配置版本,在主服務(wù)器上以及所有從服務(wù)器上。與此同時(shí),所有的 Sentinel 等待其它 Sentinel 通知的配置消息。

配置信息在__sentinel__:hello 頻道中廣播。

因?yàn)槊恳粋€(gè)配置有一個(gè)不同的版本號(hào),所以更大的版本號(hào)總是勝過(guò)更小的版本號(hào)。

例如,一開(kāi)始所有的 Sentinel 認(rèn)為主服務(wù)器 mymaster 的配置為 192.168.1.50:6379。這個(gè)配置擁有版本 1。一段時(shí)間以后,一個(gè) Sentinel 被授權(quán)以版本 2 來(lái)故障轉(zhuǎn)移。如果故障轉(zhuǎn)移成功,會(huì)廣播一個(gè)新的配置,比如說(shuō) 192.168.1.50:9000,作為版本 2。所有其他實(shí)例會(huì)看到這個(gè)配置,并相應(yīng)地更新它們的配置,因?yàn)樾碌呐渲脫碛幸粋€(gè)更大的版本號(hào)。

這意味著,Sentinel 保證第二個(gè)活性屬性:一個(gè)可以相互通信的 Sentinel 集合會(huì)統(tǒng)一到一個(gè)擁有更高版本號(hào)的相同配置上。

基本上,如果網(wǎng)絡(luò)是分割的,每個(gè)分區(qū)會(huì)統(tǒng)一到一個(gè)更高版本的本地配置。在沒(méi)有分割的特殊情況下,只有一個(gè)分區(qū),每個(gè) Sentinel 將會(huì)配置一致。

SDOWN 和 ODOWN 更多細(xì)節(jié)

正如本文已經(jīng)簡(jiǎn)要提到的,Redis Sentinel 有兩個(gè)不同的下線概念,一個(gè)被稱(chēng)為主觀下線條件(SDOWN),一個(gè)本地 Sentinel 實(shí)例的下線條件。另一個(gè)稱(chēng)為客觀下線條件(ODOWN),當(dāng)足夠的 Sentinel(至少為主服務(wù)器 quorum 參數(shù)配置的數(shù)量) 具有 SDOWN 條件時(shí)就滿足 ODOWN,并且使用 SENTINEL is-master-down-by-addr 命令從其它 Sentinel 獲得反饋。

從 Sentinel 的角度來(lái)看,如果我們沒(méi)有在配置的 is-master-down-after-milliseconds 參數(shù)的指定時(shí)間內(nèi)收到一個(gè) PING 請(qǐng)求的合法響應(yīng),就達(dá)到了 SDOWN 的條件。

PING 的可接受響應(yīng)可以是以下其中之一:

  • 回復(fù) + PONG。
  • 回復(fù) - LOADING 錯(cuò)誤。
  • 回復(fù) - MASTERDOWN 錯(cuò)誤。

其它回復(fù) (或者沒(méi)有回復(fù)) 都被認(rèn)為是不合法的。

注意,SDOWN 需要在配置的整個(gè)時(shí)間區(qū)間內(nèi)沒(méi)有收到可以接受的回復(fù),例如,如果間隔配置為 30000 毫秒(30 秒),我們每隔 29 秒收到一個(gè)可以接受的 ping 回復(fù),實(shí)例被認(rèn)為是正常工作的。

從 SDOWN 切換到 ODOWN 沒(méi)有使用強(qiáng)一致性算法,而僅僅是 gossip 的形式:如果一個(gè)指定的 Sentinel 在指定的時(shí)間范圍內(nèi)從足夠多的 Sentinel 那里獲得關(guān)于主服務(wù)器不工作的報(bào)告,SDOWN 就被提升為 ODOWN。如果這種報(bào)告不再收到,(ODOWN)標(biāo)記就會(huì)被清除。

正如已經(jīng)解釋過(guò)的,真正開(kāi)始故障轉(zhuǎn)移需要更嚴(yán)格的授權(quán),但是,如果沒(méi)有達(dá)到 ODOWN 狀態(tài),是不會(huì)觸發(fā)故障轉(zhuǎn)移的。

ODOWN 條件只適用于主服務(wù)器。對(duì)于其他的實(shí)例,Sentinel 不需要任何同意,所以從服務(wù)器和其它 Sentinel 永遠(yuǎn)都不會(huì)達(dá)到 ODOWN 狀態(tài)。

自動(dòng)發(fā)現(xiàn)(Auto discovery)

Sentinel 之間保持著連接來(lái)互相檢查彼此的可用性,互相交換信息,你不需要在每個(gè)你運(yùn)行的 Sentinel 實(shí)例中配置其他 Sentinel 的地址,因?yàn)?Sentinel 使用 Redis 主服務(wù)器的發(fā)布訂閱能力來(lái)發(fā)現(xiàn)監(jiān)控同一臺(tái)主服務(wù)器的其他 Sentinel。

這是通過(guò)向名為_(kāi)_sentinel__:hello 頻道發(fā)送問(wèn)候消息 (Hello Messages) 實(shí)現(xiàn)的。

同樣,你不需要配置連接在主服務(wù)器上的從服務(wù)器列表,因?yàn)?Sentinel 會(huì)通過(guò)詢(xún)問(wèn) Redis 自動(dòng)發(fā)現(xiàn)這個(gè)列表。

  • 每個(gè) Sentinel 每隔 2 秒向每個(gè)被監(jiān)控的主服務(wù)器和從服務(wù)器的發(fā)布訂閱頻道__sentinel__:hello 發(fā)送一條消息,報(bào)告自己的存在狀態(tài):IP 地址,端口號(hào)和 runid。
  • 每個(gè) Sentinel 訂閱了每個(gè)主服務(wù)器和從服務(wù)器的發(fā)布訂閱頻道__sentinel__:hello,尋找未知的 Sentinel。當(dāng)檢測(cè)到新的 Sentinel,就將其添加到這臺(tái)主服務(wù)器的 Sentinel 列表中。
  • 問(wèn)候消息也包括主服務(wù)器當(dāng)前的完整配置。如果另一個(gè) Sentinel 擁有一個(gè)比接收到的更老的主服務(wù)器配置,會(huì)立刻更新為新的配置。
  • 在添加一個(gè)新的 Sentinel 到主服務(wù)器前,Sentinel 總是檢查是否已經(jīng)有一個(gè)相同的 runid 或者相同地址(IP 地址和端口對(duì))的 Sentinel。如果是的話,所有匹配的 Sentinel 將會(huì)被刪除,新的被添加。