Redis Sentinel 的配置是最終一致性的,所以每個(gè)分區(qū)會(huì)被統(tǒng)一到一個(gè)可用的更高版本的配置。但是,在使用 Sentinel 的真實(shí)世界系統(tǒng)中有三個(gè)不同的角色:
為了定義系統(tǒng)的行為,我們得考慮這三個(gè)角色。
下面是一個(gè)有三個(gè)節(jié)點(diǎn)的簡(jiǎn)單網(wǎng)絡(luò),每一個(gè)節(jié)點(diǎn)運(yùn)行一個(gè) Redis 實(shí)例和一個(gè) Sentinel 實(shí)例:
http://wiki.jikexueyuan.com/project/redis-guide/images/1.png" alt="" />
在這個(gè)系統(tǒng)中,初始狀態(tài)是 Redis 3 是主服務(wù)器,Redis 1 和 Redis 2 是從服務(wù)器。分割發(fā)生了,隔斷了老的主服務(wù)器。Sentinel 1 和 2 開始故障轉(zhuǎn)移,提升 Sentinel 1 作為新的主服務(wù)器。
Sentinel 的屬性保證,Sentinel 1 和 2 現(xiàn)在擁有主服務(wù)器的最新配置。但是,Sentinel 3 仍是舊的配置,因?yàn)樗嬖谟谝粋€(gè)不同的分割中。
當(dāng)網(wǎng)絡(luò)分割恢復(fù)正常了,Sentinel 3 將會(huì)更新其配置,但是,如果有客戶端與老的主服務(wù)器被分割在一起,在分割期間會(huì)發(fā)生什么事情呢?
客戶端會(huì)繼續(xù)向 Redis 3 寫,即老的主服務(wù)器。當(dāng)分割又聚合在一起,Redis 3 將會(huì)變成 Redis 1 的從服務(wù)器,分割期間所有寫入的數(shù)據(jù)會(huì)丟失。
你可能想或者不想這種場(chǎng)景發(fā)生,取決于你的配置:
因?yàn)?Redis 是異步復(fù)制,這種場(chǎng)景下沒(méi)有完全阻止數(shù)據(jù)丟失的辦法,但是你可以使用下面的 Redis 配置選項(xiàng),來(lái)限制 Redis 3 和 Redis 1 之間的分歧:
min-slaves-to-write 1
min-slaves-max-lag 10
有了上面的配置(請(qǐng)查看 Redis 分發(fā)版本中自帶的 redis.conf 文件中的注釋獲取更多的信息),扮演主服務(wù)器的 Redis 實(shí)例如果不能寫入到至少一個(gè)從服務(wù)器,將會(huì)停止接受寫請(qǐng)求。由于復(fù)制是異步的,不能寫入的意思就是從服務(wù)器也是斷開的,或者在指定的 max-lag 秒數(shù)沒(méi)有發(fā)送異步回應(yīng) (acknowledges)。
使用這個(gè)配置,上面例子中的 Redis 3 在 10 秒鐘之后變得不可用。當(dāng)分割恢復(fù)了,Sentinel 3 的配置將會(huì)統(tǒng)一為新的,客戶端 B 可以獲取合法的配置并且繼續(xù)。
Sentinel 的狀態(tài)被持久化在 Sentinel 的配置文件中。例如,每次創(chuàng)建(領(lǐng)導(dǎo)者 leader Sentinel)或者收到新的配置,主服務(wù)器會(huì)將配置連同配置紀(jì)元持久化到磁盤中。這意味著,停止和重啟 Sentinel 進(jìn)程是安全的。
即使沒(méi)有故障轉(zhuǎn)移在進(jìn)行中,Sentinel 也會(huì)一直嘗試在被監(jiān)控的實(shí)例上設(shè)置當(dāng)前配置。尤其是:
這防止了持有舊配置(例如,因?yàn)閯倓倧姆指钪谢謴?fù))的 Sentinel 會(huì)嘗試在收到變更之前改變從服務(wù)器的配置。
也要注意,一直嘗試使用當(dāng)前配置使得故障轉(zhuǎn)移對(duì)分割具有更強(qiáng)的抵抗力的語(yǔ)義是什么:
當(dāng) Sentinel 實(shí)例準(zhǔn)備執(zhí)行故障轉(zhuǎn)移,也就是當(dāng)主服務(wù)器處于 ODOWN 狀態(tài),并且 Sentinel 從大多數(shù)已知 Sentinel 實(shí)例收到了故障轉(zhuǎn)移授權(quán),需要選擇一個(gè)合適的從服務(wù)器。
從服務(wù)器的選擇過(guò)程評(píng)估從服務(wù)器的以下信息:
一個(gè)從服務(wù)器被發(fā)現(xiàn)從主服務(wù)器斷開超過(guò)十倍于配置的主服務(wù)器超時(shí)(down-after-milliseconds 選項(xiàng)),加上從正在執(zhí)行故障轉(zhuǎn)移的 Sentinel 的角度來(lái)看主服務(wù)器也不可用的時(shí)間,將會(huì)被認(rèn)為不適合用于故障轉(zhuǎn)移并跳過(guò)。
更嚴(yán)謹(jǐn)?shù)卣f(shuō),一個(gè)從服務(wù)器的 INFO 輸出表明已從主服務(wù)器斷開超過(guò):
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
就被認(rèn)為不可靠并且被拋棄。
從服務(wù)器選擇只考慮通過(guò)了上面測(cè)試的從服務(wù)器,并且基于上面的標(biāo)準(zhǔn)排序,使用下面的順序。
如果對(duì)機(jī)器有強(qiáng)烈的偏好的話,Redis 主服務(wù)器(故障轉(zhuǎn)移以后成為從服務(wù)器)和從服務(wù)器都需要配置 slave-priority。否則,所有的實(shí)例都可以使用默認(rèn)的運(yùn)行 ID 來(lái)運(yùn)行(這是建議的設(shè)置,因?yàn)榘凑諒?fù)制偏移量來(lái)選擇從服務(wù)器要有趣得多)。
Redis 實(shí)例可以配置一個(gè)特殊的 slave-priority 值 0,這樣就一定不會(huì)被 Sentinel 選舉為新的主服務(wù)器。但是,按照這樣配置的從服務(wù)器仍然會(huì)被 Sentinel 重新配置,從而在故障轉(zhuǎn)移后復(fù)制新的主服務(wù)器,唯一的區(qū)別是永遠(yuǎn)不會(huì)變成主服務(wù)器。
Sentinel 和 Redis 身份驗(yàn)證(authentication)
當(dāng)主服務(wù)器被配置為需要客戶端傳遞密碼時(shí),作為安全措施,從服務(wù)器也需要知道這個(gè)密碼來(lái)驗(yàn)證主服務(wù)器,并且創(chuàng)建用于異步復(fù)制協(xié)議的主從連接。
使用下面的配置指令完成:
主服務(wù)器中的 requirepass 用來(lái)設(shè)置密碼驗(yàn)證,以確保實(shí)例不會(huì)處理沒(méi)有驗(yàn)證過(guò)的客戶端的請(qǐng)求。 從服務(wù)器中的 masterauth 用于從服務(wù)器驗(yàn)證主服務(wù)器,以正確的從其復(fù)制數(shù)據(jù)。
當(dāng)使用 Sentinel 就沒(méi)有單一的主服務(wù)器,因?yàn)楣收限D(zhuǎn)移以后從服務(wù)器可以扮演主服務(wù)器的角色,老的主服務(wù)器被重新配置以扮演從服務(wù)器,所以你要做的就是在你所有的主服務(wù)器和從服務(wù)器實(shí)例中設(shè)置以上指令。
這通常是一種邏輯上健全的設(shè)置,因?yàn)槟悴幌胫皇潜Wo(hù)主服務(wù)器中的數(shù)據(jù),從服務(wù)器中也應(yīng)擁有同樣可訪問(wèn)的數(shù)據(jù)。
但是,在一些不常見的情況下,你需要從服務(wù)器無(wú)需驗(yàn)證就能訪問(wèn),你仍可以通過(guò)設(shè)置從服務(wù)器的優(yōu)先級(jí)為 0(這將不允許從服務(wù)器被提升為主服務(wù)器),只為從服務(wù)器配置 masterauth 指令,不配置 requirepass 指令這樣來(lái)做到,這樣數(shù)據(jù)就可以讓未經(jīng)驗(yàn)證的客戶端讀取。
Sentinel 運(yùn)行默認(rèn)使用 TCP 端口 26379(注意,6379 是正常的 Redis 端口)。Sentinel 接受使用 Redis 協(xié)議的命令,所以你可以使用 redis-cli 或者任何其他未修改的 Redis 客戶端與 Sentinel 對(duì)話。
有兩種方式與 Sentinel 對(duì)話:可以直接查詢它來(lái)檢查被監(jiān)控的 Redis 實(shí)例的狀態(tài),看看它知道的其他 Sentinel,等等。
另外一種方式是使用發(fā)布訂閱,每當(dāng)某個(gè)事件發(fā)生時(shí),例如故障轉(zhuǎn)移,或者一個(gè)實(shí)例進(jìn)入到了一個(gè)錯(cuò)誤條件,等等,接收從 Sentinel 推過(guò)來(lái)的通知。
下面是可接受的命令清單:
從 Redis 2.8.4 開始,Sentinel 提供了用于添加,刪除和改變指定主服務(wù)器配置的 API。注意,如果你有多個(gè) Sentinel 實(shí)例,你得將改變應(yīng)用到所有的 Redis Sentinel 實(shí)例才能運(yùn)轉(zhuǎn)正常。也就是說(shuō),改變一個(gè) Sentinel 的配置不會(huì)自動(dòng)傳播到網(wǎng)絡(luò)中的其它 Sentinel。
下面是 SENTINEL 的子命令清單,用于更新 Sentinel 實(shí)例的配置。
下面是 SENTINEL SET 命令的一個(gè)例子,用于修改一個(gè)名為 objects-cache 的主服務(wù)器的 down-after-milliseconds 配置:
SENTINEL SET objects-cache-master down-after-milliseconds 1000
啟動(dòng)以后,SENTINEL SET 能用于設(shè)置所有在啟動(dòng)配置文件中可設(shè)置的配置參數(shù)。此外,還可以僅僅只改變主服務(wù)器的仲裁人數(shù)配置,而不需要使用 SENTINEL REMOVE 和 SENTINEL MONITOR 來(lái)刪除和重新添加主服務(wù)器,而只需要:
SENTINEL SET objects-cache-master quorum 5
注意,沒(méi)有與之等價(jià)的 GET 命令,因?yàn)?SENTINEL MASTER 以一種易于解析的格式(作為一個(gè)字段 - 值對(duì)數(shù)組)提供了所有的配置參數(shù)。
因?yàn)?Sentinel 實(shí)現(xiàn)的自動(dòng)發(fā)現(xiàn)機(jī)制,添加一個(gè)新的 Sentinel 到你的部署中是一個(gè)很簡(jiǎn)單的過(guò)程。所有你需要干的就是啟動(dòng)一個(gè)配置用于監(jiān)控當(dāng)前活躍主服務(wù)器的 Sentinel。在 10 秒鐘之內(nèi),Sentinel 就會(huì)獲得其他 Sentinel 的列表以及連接到主服務(wù)器的從服務(wù)器集合。
如果你想一次添加多個(gè)新的 Sentinel,建議一個(gè)一個(gè)的添加,等待所有其他的 Sentinel 知道了第一個(gè)再添加另一個(gè)。這在當(dāng)添加新 Sentinel 的過(guò)程中發(fā)生錯(cuò)誤時(shí),仍然保證在分割的一側(cè)能達(dá)到大多數(shù)時(shí)很有用。
在沒(méi)有網(wǎng)絡(luò)分割時(shí),這可以通過(guò)添加每個(gè)新的 Sentinel 時(shí)帶 30 秒的延遲來(lái)輕易實(shí)現(xiàn)。
在最后,可以使用命令 SENTINEL MASTER mastername 來(lái)檢查是否所有的 Sentinel 就監(jiān)控主服務(wù)器的 Sentinel 數(shù)量達(dá)成一致。
刪除一個(gè) Sentinel 要稍微復(fù)雜一些:Sentinel 永遠(yuǎn)不會(huì)忘記已經(jīng)發(fā)現(xiàn)的 Sentinel,即使他們?cè)诤荛L(zhǎng)一段時(shí)間內(nèi)都不可達(dá),因?yàn)槲覀儾幌雱?dòng)態(tài)改變用于授權(quán)故障轉(zhuǎn)移所需要的大多數(shù)以及創(chuàng)建新的配置版本。所以在沒(méi)有網(wǎng)絡(luò)分割情況下,需要執(zhí)行下面的步驟來(lái)刪除 Sentinel:
Sentinel 不會(huì)忘記主服務(wù)器的從服務(wù)器,即使在很長(zhǎng)時(shí)間內(nèi)都不可達(dá)。這很有用,因?yàn)檫@樣 Sentinel 能夠在網(wǎng)絡(luò)分割或者錯(cuò)誤事件恢復(fù)后正確地重新配置一個(gè)返回的從服務(wù)器。
此外,故障轉(zhuǎn)移之后,被故障轉(zhuǎn)移的主服務(wù)器事實(shí)上被添加為新主服務(wù)器的從服務(wù)器,這樣一旦恢復(fù)重新可用,就會(huì)被重新配置來(lái)復(fù)制新的主服務(wù)器。
但是,有時(shí)候你想從 Sentinel 監(jiān)控的從服務(wù)器列表中永久刪除一個(gè)從服務(wù)器(可能是舊的主服務(wù)器)。
要做到這個(gè),你需要發(fā)送 SENTINEL RESET mastername 命令到所有的 Sentinel:在接下來(lái)的 10 秒內(nèi),他們會(huì)刷新從服務(wù)器列表,只添加當(dāng)前主服務(wù)器 INFO 輸出中的正確復(fù)制的清單。
客戶端可以將 Sentinel 作為一個(gè) Redis 兼容的發(fā)布訂閱服務(wù)器(但是你不能使用 PUBLISH)來(lái)使用,來(lái)訂閱或者發(fā)布到頻道,獲取指定事件通知。
頻道名稱與事件名稱是一樣的。例如,名為 + sdown 的頻道會(huì)收到所有關(guān)于實(shí)例進(jìn)入 SDOWN 條件的通知。
簡(jiǎn)單使用 PSUBSCRIBE * 訂閱來(lái)獲得所有的消息。
下面是頻道的清單,以及使用這個(gè) API 你會(huì)收到的消息格式。第一個(gè)單詞是頻道/事件名稱,剩下的是數(shù)據(jù)的格式。
注意:指定 instance details 的地方表示提供了下面用于表示目標(biāo)實(shí)例的參數(shù):
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
標(biāo)識(shí)主服務(wù)器的部分 (從 @參數(shù)到結(jié)束) 是可選的,只在實(shí)例不是主服務(wù)器本身時(shí)指定。
Redis Sentinel 嚴(yán)重依賴于計(jì)算機(jī)時(shí)間:例如,為了了解一個(gè)實(shí)例是否可用,Sentinel 會(huì)記住最近成功回復(fù) PING 命令的時(shí)間,與當(dāng)前時(shí)間對(duì)比來(lái)了解這有多久。
但是,如果計(jì)算機(jī)時(shí)間以不可預(yù)知的方式改變了,或者計(jì)算機(jī)非常繁忙,或者某些原因進(jìn)程阻塞了,Sentinel 可能會(huì)開始表現(xiàn)得不可預(yù)知。
TILT 模式是一個(gè)特別的保護(hù)模式,當(dāng)發(fā)現(xiàn)一些會(huì)降低系統(tǒng)可靠性的奇怪問(wèn)題時(shí),Sentinel 就會(huì)進(jìn)入這種模式。Sentinel 的定時(shí)中斷通常每秒鐘執(zhí)行 10 次,所以我們期待兩次定時(shí)中斷調(diào)用之間相隔 100 毫秒左右。
Sentinel 做的就是記錄上一次定時(shí)中斷調(diào)用的時(shí)間,與當(dāng)前調(diào)用進(jìn)行比較:如果時(shí)間差是負(fù)數(shù)或者出乎意料的大(2 秒或更多),就進(jìn)入了 TILT 模式(或者如果已經(jīng)進(jìn)入了,退出 TILT 模式將被推遲)。
當(dāng)處于 TILT 模式時(shí),Sentinel 會(huì)繼續(xù)監(jiān)控一切,但是:
如果一切表現(xiàn)正常了 30 秒,將退出 TILT 模式。
(警告:還未實(shí)現(xiàn))
當(dāng)腳本運(yùn)行超過(guò)配置的腳本限制時(shí)間時(shí)返回 - BUSY 錯(cuò)誤。當(dāng)這種情況發(fā)生時(shí),在觸發(fā)故障轉(zhuǎn)移之前 Redis Sentinel 會(huì)嘗試發(fā)送 SCRIPT KILL 命令,這只有在腳本是只讀的情況下才能成功。
Sentinel 需要顯式的客戶端支持,除非系統(tǒng)被配置為執(zhí)行一個(gè)腳本,來(lái)實(shí)現(xiàn)透明重定向所有請(qǐng)求到新的主服務(wù)器實(shí)例(虛擬 IP 或其它類似系統(tǒng))??蛻舳藥?kù)實(shí)現(xiàn)的主題在 Sentinel 客戶端指引手冊(cè)中討論(請(qǐng)期待本系列后續(xù)文檔,譯者注)。