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