Redis学习(八)哨兵机制
? ? ? ? 哨兵(Sentinel)是redis高可用性的解決方案,由一個(gè)或多個(gè)哨兵實(shí)例組成的哨兵系統(tǒng),可以監(jiān)視任意多個(gè)主服務(wù)器,以及這些主服務(wù)器屬下的從服務(wù)器。
當(dāng)被監(jiān)視的主服務(wù)器下線時(shí),根據(jù)某些規(guī)則挑選一個(gè)從服務(wù)器,作為新的主服務(wù)器。接著,其他從服務(wù)器會(huì)向新的主服務(wù)器發(fā)送復(fù)制指令,并且完成復(fù)制。同時(shí),哨兵會(huì)監(jiān)視下線的原主服務(wù)器,在它重新上線后,將它也置為從服務(wù)器。
目錄
Sentinel啟動(dòng)與初始化
與服務(wù)器通信
故障檢測與處理
總結(jié)
Sentinel啟動(dòng)與初始化
1、啟動(dòng)命令
redis-sentinel /path/to/sentinel/config/sentinel.conf或 redis-server/path/to/sentinel/config/sentinel.conf --sentinel啟動(dòng)一個(gè)哨兵可以使用這兩個(gè)命令中的一個(gè),效果完全相同,當(dāng)一個(gè)哨兵啟動(dòng)時(shí),需要完成以下步驟:
2、初始化服務(wù)器
Sentinel 本質(zhì)上只是一個(gè)運(yùn)行在特殊模式下的 Redis 服務(wù)器,所以啟動(dòng) Sentinel 的第一步,就是初始化一個(gè)普通的 Redis 服務(wù)器, 具體的步驟可見Redis客戶端/服務(wù)器。
不過, 因?yàn)?Sentinel 執(zhí)行的工作和普通 Redis 服務(wù)器執(zhí)行的工作不同, 所以 Sentinel 的初始化過程和普通 Redis 服務(wù)器的初始化過程并不完全相同。比如,普通服務(wù)器在初始化時(shí)會(huì)通過載入 RDB 文件或者 AOF 文件來還原數(shù)據(jù)庫狀態(tài),但是因?yàn)?Sentinel 并不使用數(shù)據(jù)庫,所以初始化 Sentinel 時(shí)就不會(huì)載入 RDB 文件或者 AOF 文件。
下表為 Redis 服務(wù)器在 Sentinel 模式下運(yùn)行時(shí), 服務(wù)器各個(gè)主要功能的使用情況:
| 數(shù)據(jù)庫和鍵值對方面的命令, 比如?SET?、?DEL?、?FLUSHDB?。 | 不使用。 |
| 事務(wù)命令, 比如?MULTI?和?WATCH?。 | 不使用。 |
| 腳本命令,比如?EVAL?。 | 不使用。 |
| RDB 持久化命令, 比如?SAVE?和?BGSAVE?。 | 不使用。 |
| AOF 持久化命令, 比如?BGREWRITEAOF?。 | 不使用。 |
| 復(fù)制命令,比如?SLAVEOF?。 | Sentinel 內(nèi)部可以使用,但客戶端不可以使用。 |
| 發(fā)布與訂閱命令, 比如?PUBLISH?和?SUBSCRIBE?。 | SUBSCRIBE?、?PSUBSCRIBE?、?UNSUBSCRIBE?PUNSUBSCRIBE?四個(gè)命令在 Sentinel 內(nèi)部和客戶端都可以使用, 但?PUBLISH?命令只能在 Sentinel 內(nèi)部使用。 |
| 文件事件處理器(負(fù)責(zé)發(fā)送命令請求、處理命令回復(fù))。 | Sentinel 內(nèi)部使用, 但關(guān)聯(lián)的文件事件處理器和普通 Redis 服務(wù)器不同。 |
| 時(shí)間事件處理器(負(fù)責(zé)執(zhí)行?serverCron?函數(shù))。 | Sentinel 內(nèi)部使用, 時(shí)間事件的處理器仍然是?serverCron?函數(shù),?serverCron?函數(shù)會(huì)調(diào)用?sentinel.c/sentinelTimer?函數(shù), 后者包含了 Sentinel 要執(zhí)行的所有操作。 |
3、使用 Sentinel 專用代碼
啟動(dòng) Sentinel 的第二個(gè)步驟就是將一部分普通 Redis 服務(wù)器使用的代碼替換成 Sentinel 專用代碼。
- 普通 Redis 服務(wù)器使用?REDIS_SERVERPORT?常量的值作為服務(wù)器端口:#define REDIS_SERVERPORT 6379 ;而 Sentinel 則使用?REDIS_SENTINEL_PORT?常量的值作為服務(wù)器端口:#define REDIS_SENTINEL_PORT 26379
- 普通 Redis 服務(wù)器使用?redis.c/redisCommandTable?作為服務(wù)器的命令表,而 Sentinel 則使用?sentinel.c/sentinelcmds?作為服務(wù)器的命令表
sentinelcmds?命令表也解釋了為什么在 Sentinel 模式下, Redis 服務(wù)器不能執(zhí)行諸如?SET?、?DBSIZE?、?EVAL?等等這些命令 —— 因?yàn)榉?wù)器根本沒有在命令表中載入這些命令:?PING?、 SENTINEL?、?INFO?、?SUBSCRIBE?、?UNSUBSCRIBE?、?
PSUBSCRIBE?和?PUNSUBSCRIBE?這七個(gè)命令就是客戶端可以對 Sentinel 執(zhí)行的全部命令了。
4、初始化?Sentinel 狀態(tài)
在應(yīng)用了 Sentinel 的專用代碼之后,?服務(wù)器會(huì)初始化一個(gè)?sentinel.c/sentinelState?結(jié)構(gòu)(后面簡稱“Sentinel 狀態(tài)”),這個(gè)結(jié)構(gòu)保存了服務(wù)器中所有和 Sentinel 功能有關(guān)的狀態(tài) (服務(wù)器的一般狀態(tài)仍然由?redis.h/redisServer?結(jié)構(gòu)保存):
struct sentinelState {// 當(dāng)前紀(jì)元,用于實(shí)現(xiàn)故障轉(zhuǎn)移uint64_t current_epoch;// 保存了所有被這個(gè) sentinel 監(jiān)視的主服務(wù)器// 字典的鍵是主服務(wù)器的名字// 字典的值則是一個(gè)指向 sentinelRedisInstance 結(jié)構(gòu)的指針dict *masters;// 是否進(jìn)入了 TILT 模式?int tilt;// 目前正在執(zhí)行的腳本的數(shù)量int running_scripts;// 進(jìn)入 TILT 模式的時(shí)間mstime_t tilt_start_time;// 最后一次執(zhí)行時(shí)間處理器的時(shí)間mstime_t previous_time;// 一個(gè) FIFO 隊(duì)列,包含了所有需要執(zhí)行的用戶腳本list *scripts_queue;} sentinel;5、Sentinel 監(jiān)視初始化
Sentinel 狀態(tài)中的?masters?字典記錄了所有被 Sentinel 監(jiān)視的主服務(wù)器的相關(guān)信息, 其中:
- 字典的鍵是被監(jiān)視主服務(wù)器的名字。
- 而字典的值則是被監(jiān)視主服務(wù)器對應(yīng)的?sentinelRedisInstance?結(jié)構(gòu)。
每個(gè)?sentinelRedisInstance?結(jié)構(gòu)(后面簡稱“實(shí)例結(jié)構(gòu)”)代表一個(gè)被 Sentinel 監(jiān)視的 Redis 服務(wù)器實(shí)例(instance),這個(gè)實(shí)例可以是主服務(wù)器、從服務(wù)器、或者另外一個(gè) Sentinel 。
typedef struct sentinelRedisInstance {// 標(biāo)識(shí)值,記錄了實(shí)例的類型,以及該實(shí)例的當(dāng)前狀態(tài)int flags;// 實(shí)例的名字// 主服務(wù)器的名字由用戶在配置文件中設(shè)置// 從服務(wù)器以及 Sentinel 的名字由 Sentinel 自動(dòng)設(shè)置// 格式為 ip:port ,例如 "127.0.0.1:26379"char *name;// 實(shí)例的運(yùn)行 IDchar *runid;// 配置紀(jì)元,用于實(shí)現(xiàn)故障轉(zhuǎn)移uint64_t config_epoch;// 實(shí)例的地址sentinelAddr *addr;// SENTINEL down-after-milliseconds 選項(xiàng)設(shè)定的值// 實(shí)例無響應(yīng)多少毫秒之后才會(huì)被判斷為主觀下線(subjectively down)mstime_t down_after_period;// SENTINEL monitor <master-name> <IP> <port> <quorum> 選項(xiàng)中的 quorum 參數(shù)// 判斷這個(gè)實(shí)例為客觀下線(objectively down)所需的支持投票數(shù)量int quorum;// SENTINEL parallel-syncs <master-name> <number> 選項(xiàng)的值// 在執(zhí)行故障轉(zhuǎn)移操作時(shí),可以同時(shí)對新的主服務(wù)器進(jìn)行同步的從服務(wù)器數(shù)量int parallel_syncs;// SENTINEL failover-timeout <master-name> <ms> 選項(xiàng)的值// 刷新故障遷移狀態(tài)的最大時(shí)限mstime_t failover_timeout;// ...} sentinelRedisInstance;其中實(shí)例的地址addr?屬性是一個(gè)指向?sentinelAddr?結(jié)構(gòu)的指針, 這個(gè)結(jié)構(gòu)保存著實(shí)例的 IP 地址和端口號:
typedef struct sentinelAddr {char *ip;int port; } sentinelAddr;對 Sentinel 狀態(tài)的初始化將引發(fā)對?masters?字典的初始化,而masters字典的初始化是根據(jù)被載入的Sentinel配置文件來進(jìn)行的。
# 載入master1 configure #####################sentinel monitor master1 127.0.0.1 6379 2sentinel down-after-milliseconds master1 30000sentinel parallel-syncs master1 1sentinel failover-timeout master1 900000# 載入master2 configure #####################sentinel monitor master2 127.0.0.1 12345 5sentinel down-after-milliseconds master2 50000sentinel parallel-syncs master2 5sentinel failover-timeout master2 450000那么 Sentinel 將為主服務(wù)器?master1?和主服務(wù)器?master2?創(chuàng)建如圖所示的實(shí)例結(jié)構(gòu),而這兩個(gè)實(shí)例結(jié)構(gòu)又會(huì)被保存到 Sentinel 狀態(tài)的?masters?字典中。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
6、連向主服務(wù)器的網(wǎng)絡(luò)連接
初始化 Sentinel 的最后一步是創(chuàng)建連向被監(jiān)視主服務(wù)器的網(wǎng)絡(luò)連接: Sentinel 將成為主服務(wù)器的客戶端, 它可以向主服務(wù)器發(fā)送命令, 并從命令回復(fù)中獲取相關(guān)的信息。
對于每個(gè)被 Sentinel 監(jiān)視的主服務(wù)器來說, Sentinel 會(huì)創(chuàng)建兩個(gè)連向主服務(wù)器的異步網(wǎng)絡(luò)連接:
- 命令連接, 這個(gè)連接專門用于向主服務(wù)器發(fā)送命令,并接收命令回復(fù)。
- 訂閱連接, 這個(gè)連接專門用于訂閱主服務(wù)器的?__sentinel__:hello?頻道。
為什么有兩個(gè)連接?
在 Redis 目前的發(fā)布與訂閱功能中,被發(fā)送的信息都不會(huì)保存在 Redis 服務(wù)器里面,如果在信息發(fā)送時(shí),想要接收信息的客戶端不在線或者斷線,那么這個(gè)客戶端就會(huì)丟失這條信息。
因此,為了不丟失?__sentinel__:hello?頻道的任何信息,Sentinel 必須專門用一個(gè)訂閱連接來接收該頻道的信息。
而另一方面, 除了訂閱頻道之外,Sentinel 還又必須向主服務(wù)器發(fā)送命令,以此來與主服務(wù)器進(jìn)行通訊,所以Sentinel 還必須向主服務(wù)器創(chuàng)建命令連接。
并且因?yàn)?Sentinel 需要與多個(gè)實(shí)例創(chuàng)建多個(gè)網(wǎng)絡(luò)連接, 所以 Sentinel 使用的是異步連接。
與服務(wù)器通信
1、獲取主服務(wù)器信息
sentinel 默認(rèn)會(huì)每10秒一次,給主服務(wù)器發(fā)送info命令,并且通過分析info命令,來判斷當(dāng)前主服務(wù)器的信息。通過分析info命令,sentinel會(huì)得到兩方面的信息:
- 一是run_id域記錄的主服務(wù)器的運(yùn)行ID以及其role域記錄的服務(wù)器角色
- 二是關(guān)于主服務(wù)器屬下所有從服務(wù)器的信息,每一個(gè)從服務(wù)器由slave字符串開頭,每行IP記錄一個(gè)IP地址、端口號、offset(用于與主服務(wù)器aof)、lag(延遲時(shí)間)等
因此,sentinel無需建立和從服務(wù)器的連接,也可以知道從服務(wù)器的情況。sentinel只需要將info獲得的返回結(jié)果,分析并更新到sentinel的sentinelState結(jié)構(gòu)體的相應(yīng)屬性即可。另外,sentinel在更新結(jié)構(gòu)體時(shí),還會(huì)分析每一個(gè)從服務(wù)器是否存在,如果是現(xiàn)有的則更新結(jié)構(gòu)體,如果不是現(xiàn)有的則新增一個(gè)結(jié)構(gòu)體。
? ? ? ? ??
從上述可知,主從服務(wù)器sentinelRedisInstance結(jié)構(gòu)的主要區(qū)別:
2、獲取從服務(wù)器信息
當(dāng) sentinel 發(fā)現(xiàn)有新的從服務(wù)器,除了會(huì)為其創(chuàng)建實(shí)例結(jié)構(gòu),還會(huì)與其建立連接,連接也是包括訂閱連接和命令連接。且默認(rèn)下,每10秒也會(huì)給從服務(wù)器發(fā)送info命令。
? ? ? ? ? ? ? ? ? ? ? ? ? ??
根據(jù)info命令,可以獲取從服務(wù)器的以下主要信息:從服務(wù)器運(yùn)行ID、從服務(wù)器角色、主服務(wù)器ip與端口號、主從服務(wù)器連接狀態(tài)、從服務(wù)器優(yōu)先級、從服務(wù)器的復(fù)制偏移量。
根據(jù)這些信息,Sentinel 會(huì)對從服務(wù)器的實(shí)例結(jié)構(gòu)?sentinelRedisInstance?進(jìn)行更新。
3、與主從服務(wù)器進(jìn)行通信
默認(rèn)情況下,sentinel會(huì)每兩秒一次,通過命令連接向被其監(jiān)聽的所有主服務(wù)器和從服務(wù)器發(fā)送以下格式的命令:
publish __sentinel__:hello “<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>”這條命令向?__sentinel__:hello頻道發(fā)送了一條信息,信息的內(nèi)容中:
- s_ 開頭的參數(shù)記錄的是sentinel本身的信息:分別為Sentinel的IP地址、端口號、運(yùn)行ID以及當(dāng)前配置紀(jì)元
- m_ 開頭的是監(jiān)聽的主服務(wù)器相關(guān)的信息:分別是主服務(wù)器的名字、IP地址、端口號以及當(dāng)前的配置紀(jì)元
sentinel會(huì)和每個(gè)其監(jiān)聽的服務(wù)器建立發(fā)布訂閱連接,對于每個(gè)與Sentinel連接的服務(wù)器,Sentinel即通過命令連接向服務(wù)器的__sentinel__:hello?頻道發(fā)送信息,又通過訂閱連接從服務(wù)器的__sentinel__:hello?頻道接受信息,Sentinel會(huì)一直監(jiān)聽__sentinel__:hello 頻道,直到與服務(wù)器連接斷開為止。
對于監(jiān)視同一服務(wù)器的多個(gè)Sentinel來說,一個(gè)Sentinel發(fā)送的信息會(huì)被其他的Sentinel接收到,這些信息會(huì)被用于更新其他Sentinel對發(fā)送信息的Sentinel的認(rèn)知,也會(huì)被用于更新其他Sentinel對被監(jiān)視服務(wù)器的認(rèn)知。
sentinel接收到信息將與sentinel自己的運(yùn)行id進(jìn)行比對,如果一致則表示信息是自己發(fā)送的,sentinel將丟棄不處理信息;如果不一致表示是其他sentinel發(fā)送的命令,則會(huì)進(jìn)行比對并更新相應(yīng)內(nèi)容(因?yàn)榘l(fā)布和訂閱都在同一頻道,所以自己會(huì)收到自己在此頻道發(fā)布的信息)。
4、更新sentinels字典
sentinel為主服務(wù)器建立的實(shí)例結(jié)構(gòu)中的?sentinels?字典除了保存自身信息,還會(huì)保存其他所有同樣監(jiān)視這個(gè)主服務(wù)器的sentinel的信息,字典的鍵是sentinel的ip:port,值是對應(yīng)的?sentinel實(shí)例結(jié)構(gòu)。
當(dāng)一個(gè) Sentinel 接收到其他的 Sentinel 發(fā)來的信息時(shí)(發(fā)送信息的為源Sentinel,接受信息的為目標(biāo)Sentinel),目標(biāo)Sentinel會(huì)從信息中分析并提取出以下信息:
- 源Sentinel的IP地址、端口號、運(yùn)行ID以及當(dāng)前配置紀(jì)元;
- 源Sentinel正在監(jiān)視的主服務(wù)器的名字、IP地址、端口號以及當(dāng)前的配置紀(jì)元
根據(jù)信息中的主服務(wù)器參數(shù),目標(biāo)Sentinel會(huì)在自己的Sentinel狀態(tài)的 masters 字典中查找相應(yīng)的主服務(wù)器實(shí)例結(jié)構(gòu),然后根據(jù)提取出的 Sentinel 參數(shù),檢查主服務(wù)器實(shí)例結(jié)構(gòu)的 sentinels 字典中源Sentinel的實(shí)例結(jié)構(gòu)是否存在。
- 如果源Sentinel的實(shí)例結(jié)構(gòu)已經(jīng)存在,那么對源Sentinel的實(shí)例結(jié)構(gòu)進(jìn)行更新。
- 如果源Sentinel的實(shí)例結(jié)構(gòu)不存在,說明源Sentinel是剛剛才開始監(jiān)視主服務(wù)器的新的Sentinel,目標(biāo)Sentinel會(huì)為源Sentinel創(chuàng)建一個(gè)新的實(shí)例結(jié)構(gòu),并將這個(gè)實(shí)例結(jié)構(gòu)添加到 sentinels 字典里面,完成對于新的Sentinel的認(rèn)知。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
由上可以看出,一個(gè)Sentinel可以通過分析接收到的頻道信息獲知其他Sentinel的存在,并通過發(fā)送頻道信息來讓其他Sentinel知道自己的存在,所以用戶在使用Sentinel的時(shí)候并不需要提供各個(gè)Sentinel的地址信息,監(jiān)視一個(gè)主服務(wù)器的各個(gè)Sentinel能自動(dòng)互相發(fā)現(xiàn)對方的存在。
5、創(chuàng)建連向其他sentinel的連接
當(dāng)sentinel發(fā)現(xiàn)其他sentinel,不僅會(huì)記錄其結(jié)構(gòu)信息,還會(huì)建立一個(gè)命令連接,而新的sentinel也會(huì)向該sentinel建立命令連接。最終監(jiān)視主服務(wù)器的多個(gè)sentinel將形成網(wǎng)絡(luò)。
另外,sentinel不會(huì)和其他sentinel建立訂閱連接,因?yàn)椴恍枰嗛喯嚓P(guān)信息。sentinel之間發(fā)送命令和訂閱信息,只需要互相用命令連接發(fā)送即可。
故障檢測與處理
1、檢測主觀下線狀態(tài)
默認(rèn)情況下,sentinel會(huì)每秒1次,向所有與它創(chuàng)建了命令連接的實(shí)例(包括主服務(wù)器、從服務(wù)器、其他Sentinel)發(fā)送ping命令,通過實(shí)例返回回復(fù)判斷實(shí)例是否在線。
有效的回復(fù)包括pong、loading和mastdown,無效的回復(fù)包括超時(shí)的回復(fù)以及前三個(gè)之外的回復(fù)。
在sentinel的配置文件中,down_after_milliseconds指定了sentinel判斷主觀下線的方式,主服務(wù)器連續(xù)沒給出正確的回復(fù)超過這個(gè)設(shè)定的時(shí)間,則表示該主服務(wù)器被這個(gè)sentinel認(rèn)定為主觀下線。
此時(shí),sentinel會(huì)在自身記錄主服務(wù)器的flags加上一個(gè)標(biāo)簽,使主服務(wù)器此時(shí)的flags標(biāo)簽變?yōu)?strong>SRI_MASTER | SRI_S_DOWN。
配置主觀下線的down_after_milliseconds,不僅sentinel會(huì)對該主服務(wù)器進(jìn)行這樣的判斷,也同樣會(huì)將該參數(shù)帶到該主服務(wù)器下的全部從服務(wù)器。
另外,不同的sentinel對同一個(gè)主服務(wù)器,設(shè)定的主觀下線的值可以不同。每個(gè)sentinel會(huì)按照自身的配置文件,來判斷檢測的主服務(wù)器是否主觀下線。
主觀下線狀態(tài)可理解為當(dāng)前的Sentinel主觀的認(rèn)為此服務(wù)器已經(jīng)下線,但不代表這個(gè)服務(wù)器真的下線,是否真的下線還要看其他也同樣監(jiān)視這個(gè)服務(wù)器的Sentinel是不是也同樣主觀認(rèn)為此服務(wù)器已是下線狀態(tài),當(dāng)超過一定數(shù)量的監(jiān)視者Sentinel都主觀認(rèn)為此服務(wù)器處于下線狀態(tài)了,那么此時(shí)才會(huì)真的認(rèn)為此服務(wù)器是已經(jīng)下線的,也就是客觀下線狀態(tài),然后進(jìn)行故障轉(zhuǎn)移。
2、檢測客觀下線狀態(tài)
發(fā)送檢測主觀下線命令
當(dāng)sentinel認(rèn)定該主服務(wù)器主觀下線,會(huì)同時(shí)給其他幾個(gè)監(jiān)測此主服務(wù)器的sentinel發(fā)送命令,確認(rèn)在其他sentinel處是否也認(rèn)為該主服務(wù)器主觀下線。命令格式為:
sentinel is-master-down-by-addr <ip><port> <current_epoch> <runid>其中,runid?如果是 * ,表示僅僅檢測該主服務(wù)器是否主觀下線,如果是用sentinel的運(yùn)行id,則表示選舉領(lǐng)頭sentinel。
接收命令回復(fù)
當(dāng)目標(biāo)Sentinel收到源Sentinel的?is-master-down-by-addr命令后,目標(biāo)sentinel會(huì)返回包含三個(gè)參數(shù)的multi bulk回復(fù),如下:
- <down_state>:目標(biāo)sentinel對該主服務(wù)器的檢查結(jié)果,1表示該sentinel也認(rèn)為主服務(wù)器主觀下線,0表示未下線。
- <leader_runid>:*?或者?sentinel運(yùn)行ID,*?表示僅僅用于檢測該主服務(wù)器是的下線狀態(tài),sentinel id表示局部領(lǐng)頭Sentinel的運(yùn)行ID用于選舉領(lǐng)頭的Sentinel。
- <leader_epoch>:領(lǐng)頭紀(jì)元,用于選舉領(lǐng)頭的Sentinel。
3、選舉領(lǐng)頭Sentinel
根據(jù)其他Sentinel的is-master-down-by-addr命令回復(fù),當(dāng)前Sentinel將統(tǒng)計(jì)其他同意主服務(wù)器已下線的Sentinel的數(shù)量,當(dāng)這一數(shù)量達(dá)到配置指定的判斷客觀下線所需數(shù)量時(shí)(配置文件中設(shè)定的quorum的值),則sentinel將此主服務(wù)器的實(shí)例結(jié)構(gòu)的flags屬性的 SRI_MASTER|SRI_S_DOWN|SRI_O_DOWN?打開,認(rèn)為該主服務(wù)器客觀下線。
不同的sentinel可以設(shè)置不同的客觀下線數(shù)量,因此可能部分sentinel認(rèn)為主服務(wù)器客觀下線,另一部分認(rèn)為還沒客觀下線。
當(dāng)一個(gè)主服務(wù)器被判定為客觀下線,監(jiān)視該主服務(wù)器的各個(gè)sentinel,會(huì)協(xié)商選舉一個(gè)領(lǐng)頭sentinel,對下線主服務(wù)器進(jìn)行故障轉(zhuǎn)移工作。具體方式如下:
根據(jù)命令請求的先后順序不同,可能會(huì)有某個(gè)Sentinel的sentinelis-master-down-by-addr命令比其他Sentinel都更快到達(dá),從而在這次領(lǐng)頭選舉中勝出,然后領(lǐng)頭sentinel將對主服務(wù)器進(jìn)行故障轉(zhuǎn)移。
需要注意的是,Sentinel發(fā)送的命令還是有可能會(huì)同時(shí)到達(dá)的,導(dǎo)致沒法選取超過半數(shù)的領(lǐng)頭,所以Redis這里采取的是其改進(jìn)的raft分布式一致性算法,若沒有選舉出領(lǐng)頭,則會(huì)讓所以參與選舉的候選Sentinel都隨機(jī)的睡眠一段時(shí)間,先蘇醒的Sentinel會(huì)第一時(shí)間發(fā)送選舉的命令,所以最終還是會(huì)選出領(lǐng)頭的Sentinel。
4、故障轉(zhuǎn)移
選舉領(lǐng)頭后,領(lǐng)頭sentinel將進(jìn)行故障轉(zhuǎn)移,工作包括:
(1)選出新主服務(wù)器
sentinel會(huì)將下線的主服務(wù)器的從服務(wù)器列表中,選出一個(gè)從服務(wù)器,選擇規(guī)則如下:
- 不考慮已經(jīng)下線和斷線的從服務(wù)器,以保證選出的是正常在線的。
- 不考慮最近5秒內(nèi)沒有回復(fù)過領(lǐng)頭sentinel的info命令的從服務(wù)器,以保證選出的是成功通信的。
- 不考慮所有和已下線主服務(wù)器斷開連接超過down-after-millisecond*10毫秒的從服務(wù)器,以保證選出的是數(shù)據(jù)最新的。
- 將剩余的從服務(wù)器,按照從服務(wù)器優(yōu)先級選擇主服務(wù)器。
- 如果優(yōu)先級一樣,則按照偏移量最大的選擇。
- 如果優(yōu)先級和偏移量都一樣的,按照運(yùn)行ID最小的作為主服務(wù)器。
選出主服務(wù)器后,sentinel給其發(fā)送slaveof no one命令,讓其變成主服務(wù)器。并且,會(huì)每秒一次的頻率發(fā)送info命令給新主服務(wù)器(正常是10秒一次發(fā)送info),直到回復(fù)中role從slave變成master,表示升級成功。
(2)修改其他從服務(wù)器的復(fù)制目標(biāo)
即給其余的從服務(wù)器,發(fā)送slaveof <new_ip> <new_port>,讓其余的從服務(wù)器重新選擇新的主服務(wù)器執(zhí)行復(fù)制操作。
(3)將舊主服務(wù)器變成從服務(wù)器
由于其已經(jīng)下線,無法直接發(fā)送slaveof命令,sentinel會(huì)將其保存在實(shí)例結(jié)構(gòu)里面,監(jiān)控并待其重新上線,再發(fā)送命令,讓其變?yōu)樾碌闹鞣?wù)器的從服務(wù)器。
總結(jié)
- Sentinel 只是一個(gè)運(yùn)行在特殊模式下的 Redis 服務(wù)器,它使用了和普通模式不同的命令表,所以 Sentinel 模式能夠使用的命令和普通 Redis 服務(wù)器能夠使用的命令不同。
- Sentinel 會(huì)讀入用戶指定的配置文件, 為每個(gè)要被監(jiān)視的主服務(wù)器創(chuàng)建相應(yīng)的實(shí)例結(jié)構(gòu), 并創(chuàng)建連向主服務(wù)器的命令連接和訂閱連接, 其中命令連接用于向主服務(wù)器發(fā)送命令請求, 而訂閱連接則用于接收指定頻道的消息。
- Sentinel 通過向主服務(wù)器發(fā)送?INFO?命令來獲得主服務(wù)器屬下所有從服務(wù)器的地址信息, 并為這些從服務(wù)器創(chuàng)建相應(yīng)的實(shí)例結(jié)構(gòu), 以及連向這些從服務(wù)器的命令連接和訂閱連接。
- 在一般情況下, Sentinel 以每十秒一次的頻率向被監(jiān)視的主服務(wù)器和從服務(wù)器發(fā)送?INFO?命令, 當(dāng)主服務(wù)器處于下線狀態(tài), 或者 Sentinel 正在對主服務(wù)器進(jìn)行故障轉(zhuǎn)移操作時(shí), Sentinel 向從服務(wù)器發(fā)送?INFO?命令的頻率會(huì)改為每秒一次。
- 對于監(jiān)視同一個(gè)主服務(wù)器和從服務(wù)器的多個(gè) Sentinel 來說, 它們會(huì)以每兩秒一次的頻率,通過向被監(jiān)視服務(wù)器的?__sentinel__:hello頻道發(fā)送消息來向其他 Sentinel 宣告自己的存在。
- 每個(gè) Sentinel 也會(huì)從?__sentinel__:hello?頻道中接收其他 Sentinel 發(fā)來的信息,并根據(jù)這些信息為其他 Sentinel 創(chuàng)建相應(yīng)的實(shí)例結(jié)構(gòu),以及命令連接。
- Sentinel 只會(huì)與主服務(wù)器和從服務(wù)器創(chuàng)建命令連接和訂閱連接,Sentinel 與 Sentinel 之間則只創(chuàng)建命令連接。
- Sentinel 以每秒一次的頻率向?qū)嵗?#xff08;包括主服務(wù)器、從服務(wù)器、其他 Sentinel)發(fā)送?PING?命令, 并根據(jù)實(shí)例對?PING?命令的回復(fù)來判斷實(shí)例是否在線: 當(dāng)一個(gè)實(shí)例在指定的時(shí)長中連續(xù)向 Sentinel 發(fā)送無效回復(fù)時(shí), Sentinel 會(huì)將這個(gè)實(shí)例判斷為主觀下線。
- 當(dāng) Sentinel 將一個(gè)主服務(wù)器判斷為主觀下線時(shí), 它會(huì)向同樣監(jiān)視這個(gè)主服務(wù)器的其他 Sentinel 進(jìn)行詢問, 看它們是否同意這個(gè)主服務(wù)器已經(jīng)進(jìn)入主觀下線狀態(tài)。
- 當(dāng) Sentinel 收集到足夠多的主觀下線投票之后, 它會(huì)將主服務(wù)器判斷為客觀下線, 并發(fā)起一次針對主服務(wù)器的故障轉(zhuǎn)移操作。
?
?
?
參考文章:
《Redis設(shè)計(jì)與實(shí)現(xiàn)》
?
總結(jié)
以上是生活随笔為你收集整理的Redis学习(八)哨兵机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: windows 命令行创建虚拟WIFI
- 下一篇: android虚拟wifi设置,win7