目錄
- 一、基本概念和架構
- 1.1 基本概念
- 1.2 架構
- 二、部署演示
- 2.1 部署主從節點
- 2.2 部署哨兵節點
- 2.3 故障轉移演示
- 三、客戶端連接(配置提供者)
- 3.1 代碼
- 3.2 原理
- 四、實作原理
- 4.1 三個定時任務
- 4.2 主觀下線和客觀下線
- 4.3 領導者Sentinel節點選舉
- 4.4 故障轉移
一、基本概念和架構
1.1 基本概念
哨兵,Redis sentinel,在主從復制的基礎上實作故障恢復的自動化,其核心功能是主節點(master)的自動故障轉移,
主要功能:
- 監控(Monitor):哨兵不斷檢查主節點和從節點是否正常作業,
- 自動故障轉移(Automatic failover):主節點不正常時,哨兵啟動自動故障轉移,它會將失效主節點的其中一個從節點升級為新的主節點,并讓其他從節點從這個新的主節點復制資料,
- 配置提供者(Configuration provider):客戶端可以通過哨兵來獲取主節點地址,
- 通知(Notification):哨兵可以把故障轉移結果通知給客戶端,
1.2 架構

它由兩部分組成,哨兵節點和資料節點:
- 哨兵節點:哨兵系統由一個或多個哨兵節點組成,哨兵節點是特殊的redis節點,不存盤資料,
- 資料節點:主節點和從節點都是資料節點,
redis sentinel是一個分布式的架構,其中包含若干個sentinel節點,對于節點的故障判斷是由多個獨立的sentinel節點共同完成,這樣可以有效防止誤判,多個sentinel節點使得即使個別sentinel節點不可用,整個sentinel節點集合依然是健壯的,
二、部署演示
整體部署在一臺機器上(192.168.118.129 ),通過不同的埠號來區分主從節點以及哨兵節點,
2.1 部署主從節點
部署一臺主節點(埠號為6379),2臺從節點(埠號分別為6380和6381),
把6380配置為6379的slave,

把6381配置為6379的slave,
查看master節點的復制資訊
2.2 部署哨兵節點
配置三個哨兵節點,和主從在同一臺機器上(192.168.118.129),用三個不同的埠號來區分(分別為26379,26380,26381),
哨兵節點是特殊的redis節點,有特殊的配置,針對每一個哨兵分別建立一個組態檔,
以26379哨兵為例,建立sentinel26379.conf組態檔,基本配置如下:

sentinel monitor mymaster 193.168.129 6379 2
這句是哨兵節點的核心配置,代表這個哨兵監控193.168.129: 6379這個master節點,且命名為mymaster,2代表至少有兩個哨兵同意才能認定主節點產生故障并且進行故障轉移,
按照上述步驟配置sentinel26380.conf和sentinel26381.conf,至此,三個哨兵節點配置完成,
接下來啟動哨兵節點,有兩種方法,兩個方法等效
-
src/redis-sentinel sentinel26379.conf -
src/redis-server sentinel26379.conf --sentinel
一次啟動三個哨兵,啟動后可以查看,

啟動后哨兵節點會發現主節點,以及主節點對應的salve節點,同時哨兵節點會發現彼此,哨兵節點啟動后最終的結構如下,

2.3 故障轉移演示
演示主節點down機后哨兵進行自動故障轉移的case,目前主節點是6379節點,
殺掉主節點的行程

遷移
主節點已經被遷移成了6380節點,

轉移后組態檔也被自動做了修改,

三、客戶端連接(配置提供者)
哨兵作為配置的提供者,客戶端可以直接基于哨兵進行連接,而無需直到具體主節點的ip,這樣實作了和主節點的解耦,當主節點down機后,哨兵重新選主,對客戶端透明,
3.1 代碼
public static void main(String[] args)
{
String masterName="mymaster";// 主節點名字
Set<String> sentinels=new HashSet<>();//哨兵集合
sentinels.add("192.168.118.129:26379");
sentinels.add("192.168.118.129:26380");
sentinels.add("192.168.118.129:26381");
JedisSentinelPool jedisSentinelPool=new JedisSentinelPool(masterName,sentinels);
Jedis jedis= jedisSentinelPool.getResource();
jedis.set("name","cnblogs-new");
System.out.println(jedis.get("name"));
jedisSentinelPool.close();
}
執行結果:
[main] INFO redis.clients.jedis.JedisSentinelPool - Trying to find master from available Sentinels...
[main] INFO redis.clients.jedis.JedisSentinelPool - Redis master running at 192.168.118.129:6380, starting Sentinel listeners...
[main] INFO redis.clients.jedis.JedisSentinelPool - Created JedisPool to master at 192.168.118.129:6380
cnblogs-new
可以看到通過哨兵找到了master節點,
3.2 原理
核心實作在JedisSentinelPool的建構式中
private HostAndPort initSentinels(Set<String> sentinels, final String masterName) {
HostAndPort master = null;
log.info("Trying to find master from available Sentinels...");
for (String sentinel : sentinels) {
final HostAndPort hap = HostAndPort.parseString(sentinel);
log.debug("Connecting to Sentinel {}", hap);
jedis = new Jedis(hap.getHost(), hap.getPort(), sentinelConnectionTimeout, sentinelSoTimeout);
List<String> masterAddr = jedis.sentinelGetMasterAddrByName(masterName); //查找master
master = toHostAndPort(masterAddr);
return master;
}
}
通過代碼可以發現:
-
遍歷哨兵節點
-
連接哨兵節點
-
通過哨兵節點獲取master節點
sentinelGetMasterAddrByName,改方法內部呼叫了redis的命令來實作sentinel get-master-addr-by-name mymaster
上述代碼省略了一部分,訂閱,
for (String sentinel : sentinels) {
final HostAndPort hap = HostAndPort.parseString(sentinel);
MasterListener masterListener = new MasterListener(masterName, hap.getHost(), hap.getPort());
// whether MasterListener threads are alive or not, process can be stopped
masterListener.setDaemon(true);
masterListeners.add(masterListener);
masterListener.start();
}
為每一個sentinel節點獨立啟動一個執行緒,利用redis的發布訂閱功能,每個執行緒訂閱sentinel節點上切換master的相關頻道+switch-master
public void onMessage(String channel, String message) {
String[] switchMasterMsg = message.split(" ");
if (masterName.equals(switchMasterMsg[0])) {
initPool(toHostAndPort(Arrays.asList(switchMasterMsg[3], switchMasterMsg[4])));
} else {
log.debug("Ignoring message on +switch-master for master name {}, our master name is {}",switchMasterMsg[0], masterName);
}
}
發現當前master發生了switch,使用initPool重新初始化連接池,
四、實作原理
4.1 三個定時任務
通過監控來判斷節點是否不可達,sentinel通過三個定時任務來完成后對各個節點的監控和發現,
Sentinel節點定時執行info命令來獲取拓撲資訊
每隔10秒執行
- 通過向master 執行info可以拿到從節點的資訊(這就解釋了為什么sentinel沒有顯示配置從節點,但是可以監發現從節點),
- 從節點加入,可以自動感知,
- 節點不可達或者故障轉移后,可以通過info實時拿到拓撲資訊,
Sentinel節點發布和訂閱 _sentinel_hello頻道
每隔兩秒執行
每隔2秒,每隔sentinel節點會向master的_sentinel_hello 頻道發送自身的節點資訊,以及自己對master狀態的判斷,同時每個sentinel也會訂閱改頻道,最 終實作了sentinel節點之間的互相發現以及彼此交換自己對主節點狀態的判斷,作為客觀下線的依據,
Sentinel節點向其余節點發送ping命令
每隔1秒執行
實作對每個節點的監控,這個定時任務是節點失敗判定的重要依據,
4.2 主觀下線和客觀下線
一個引數: down-after-milliseconds
# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# Number of milliseconds the master (or any attached replica or sentinel) should
# be unreachable (as in, not acceptable reply to PING, continuously, for the
# specified period) in order to consider it in S_DOWN state (Subjectively
# Down).
#
# Default is 30 seconds.
主觀下線
上一節里面的ping操作,如果超過 down-after-milliseconds沒有得到回復,sentinel會把改節點做失敗判斷,叫做主觀下線,就是當前sentinel一家認為這個節點是失敗的,有可能有誤判,
客觀下線
當sentinel對master做了主觀下線后會通過命令: sentinel is-master-down-by-addr來詢問其他sentinel 節點對主節點是否下線的判斷,當超過
總結舉例
master相當于一個嫌疑人,在審判,法律規定必須要3(quorum)個陪審員都認為有罪,才會判斷為有罪,當任何一個陪審員認為嫌疑人有罪的時候,就問其他陪審員的意見,如果最侄訓總下來發現有3個陪審員認為有罪,則最終才會判斷master有罪,通過多個確認來減少誤判的可能,
客觀下線是針對master節點的,slave節點只需要主觀下線即可,
4.3 領導者Sentinel節點選舉
當最終對主節點進行客觀下線后,并不是馬上進行故障轉移,而是進入領導者sentinel節點的選舉,因為最終的故障轉移由一個sentinel節點來完成,這個節點就是領導者sentinel節點,
領導者選取使用的演算法是raft演算法,(參考2),是一個共識演算法,大致思路如下,
- 每個sentinel節點都有資格成為領導者,當它確認主節點主觀下線后,向其他sentinel節點發送
is-master-down-by-addr,要求將自己設定為領導者,當然給自己投了一票 - 其他sentinel收到命令后,如果沒有同意過其他sentinel
is-master-down-by-addr命令,則同意該請求(只投一次同意票), - 如果sentinel節點發現自己的票數已經大于或者等于max(quorum, num(sentinels)/2+1),那么它將會成為領導者sentinel節點
- 如果本次沒有選舉出領導者,將進入下一次選舉,
S1最先完成了客觀下線,
- 向S2請求,S2第一次收到,恢復YES
- 向S3請求,S3第一次收到,恢復YES
S1得到兩票,滿足條件,成為leader,
| 節點 | 發出同意的節點 | 接受同意的節點 |
|---|---|---|
| S1 | S2,S3 | |
| S2 | S1 | |
| S3 | S1 |
4.4 故障轉移
重新選取master
當領導者sentinel選舉完成后,由該sentinel節點完成故障轉移,整體流程如下,
-
過濾不健康節點是指主觀下線,斷線的salve
-
先比較replica_priority, 值越小,優先級越高
-
如果priority相同,則選擇復制偏移量最大的節點(最接近原來master的節點,資料最全)
-
如果偏移量相同,則選擇runid最小的節點
設定程序
- 領導者sentinel通過執行replicaof no one命令讓選舉出來的最新節點成為最新的master
- 領導者sentinel向其他從節點發送 replicaof 命令,讓其成為最新master的從節點
- 同時將已經下線的原主節點設定為新master的從節點,等其上線后自動成為新的主節點的從節點,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/247139.html
標籤:其他
