1. 程式人生 > >Redis之主從複製(Sentinel)

Redis之主從複製(Sentinel)

基於Redis自身的主從複製模式,一旦Master掛掉,那麼需要手動將Slave節點晉升為Master,而且還需要通知應用方更新Master節點地址,所以這種方式肯定不能接受。所以為了解決這個Redis高可用問題,Redis哨兵即Sentinel誕生。

一Sentinel概念

1.1 主從複製

Redis主從複製模式,可以將主節點資料改變同步給從節點,這樣從節點就起到了2個作用:備份和擴充套件主節點讀的能力。

問題:

# 主節點出現問題,需要手動切換從節點為主節點,你並且通知客戶端主節點變化

# 主節點寫的能力受單機限制

# 主節點儲存能力受單機限制

1.2Sentinel的高可用性

當主節點出現故障的時候,Redis Sentinel能夠自動完成故障發現和故障轉移。並通知應用方從而實現真正的高可用。

Redis Sentinel 是一個分散式架構,其中包含     若干個Sentinel節點和Redis資料節點,每一個Sentinel會對資料節點和其他Sentinel節點進行監控,當他發現節點不可達時,會對節點做下線標識。如果被標識的是主節點,他還會和其他節點Sentinel節點協商,當大多數Sentinel節點都認為主節點不可達的時候,會選舉一個Sentinel節點來完成自動故障轉移的工作,並且會將這個變化實時通知給Redis應用方。整個過程是自動的,完全不需要人工來干預。

注意: Sentinel也是Redis節點,只不過他不是用於儲存資料。

1.3Sentinel的功能

# 監控: Sentinel節點會定期檢測其他Sentinel節點和Redis資料節點

# 通知: Sentinel會將故障轉移的結果通知給應用方

# 主節點故障轉移: 選出新主節點,然後維護後續正確的主從關係

二Sentinel 安裝部署

2.1 部署拓撲圖


2.2 部署Redis資料節點

2.2.1 配置主節點

port 6379

bind 192.168.1.201

daemonize yes

pidfile /opt/app/sentinel/master/redis.pid

logfile /opt/app/sentinel/master/logs/redis.log

appendonly yes

dir /opt/app/sentinel/master/data

啟動主節點:bin/redis-servercon/redis.conf

2.2.2 配置從節點

Slave-01配置:

port 6379

bind 192.168.1.202

daemonize yes

pidfile /opt/app/sentinel/slave1/redis.pid

logfile /opt/app/sentinel/slave1/logs/redis.log

appendonly yes

dir /opt/app/sentinel/slave1/data

slaveof 192.168.1.201 6379

Slave-02配置:

port 6379

bind 192.168.1.203

daemonize yes

pidfile /opt/app/sentinel/slave2/redis.pid

logfile /opt/app/sentinel/slave2/logs/redis.log

appendonly yes

dir /opt/app/sentinel/slave2/data

slaveof 192.168.1.201 6379

啟動從節點

bin/redis-server conf/redis.conf

2.2.3 確認主從關係

bin/redis-cli -h 192.168.1.201 -p 6379 inforeplication

檢查主從關係是否確立


2.3 部署Sentinel節點

# monitor 指定需要監控主節點

sentinel monitor <master-name> <ip><redis-port> <quorum>

master-name:指定的master名字

ip: 要監聽的資料主節點節點IP地址

redis-port:要監聽的資料主節點埠

quorum:為確認這個主伺服器已下線所需要的最少Sentinel數量

# down-after-milliseconds 指定了 Sentinel 認為伺服器已經斷線所需的毫秒數

sentinel down-after-milliseconds<master-name> <milliseconds>

# failover-timeout 指定了故障轉移的超時時間,

sentinel failover-timeout <master-name><milliseconds>

# parallel-syncs 指定了在執行故障轉移時, 最多可以有多少個從伺服器同時對新的主伺服器進行同步

sentinel parallel-syncs mymaster 1

2.3.1 配置和啟動三個Sentinel節點

Sentinel1節點:

port 26379

bind 0.0.0.0

dir "/opt/app/sentinel/sentinel1/data"

daemonize yes

pidfile /opt/app/sentinel/sentinel1/sentinel.pid

logfile"/opt/app/sentinel/sentinel1/logs/sentinel.log"

sentinel monitor mymaster 192.168.1.201 6379 2

sentinel down-after-milliseconds mymaster 30000

sentinel failover-timeout mymaster 180000

sentinel parallel-syncs mymaster 1

Sentinel2節點:

port 26379

bind 0.0.0.0

dir "/opt/app/sentinel/sentinel2/data"

daemonize yes

pidfile /opt/app/sentinel/sentinel2/sentinel.pid

logfile "/opt/app/sentinel/sentinel2/logs/sentinel.log"

sentinel monitor mymaster 192.168.1.201 6379 2

sentinel down-after-milliseconds mymaster 30000

sentinel failover-timeout mymaster 180000

sentinel parallel-syncs mymaster 1

Sentinel3節點:

port 26379

bind 0.0.0.0

dir "/opt/app/sentinel/sentinel3/data"

daemonize yes

pidfile /opt/app/sentinel/sentinel3/sentinel.pid

logfile "/opt/app/sentinel/sentinel3/logs/sentinel.log"

sentinel monitor mymaster 192.168.1.201 6379 2

sentinel down-after-milliseconds mymaster 30000

sentinel failover-timeout mymaster 180000

sentinel parallel-syncs mymaster 1

檢視sentinel資訊

bin/redis-cli -h 192.168.1.201 -p 6379 infosentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=mymaster,status=ok,address=192.168.1.201:6379,slaves=2,sentinels=3

2.3.2 配置優化

# sentinel master

需要監視的主節點IP和埠以及quorum,quorum這個表示多少個sentinel節點認為主節點已經掛掉了,才視為主節點下線,即客觀下線; 同時quorum還跟sentinel節點的leader選舉有關係,至少要max(quorum,sentinel節點數/2 + 1)個sentinel節點參加選舉,才能選舉出leader,從而進行故障轉移。

# sentinel down-after-milliseconds

每一個sentinel節點都會向主節點,從節點和其他sentinel節點1秒鐘ping一次。在down-after-milliseconds毫秒內沒有進行回覆,sentinel節點就會判定該節點失敗,這個行為叫做主觀下線。

# sentinel parallel-syncs

當sentinel領導者開始進行故障轉移的時候,選出新的主節點,原來的從節點會向新的主節點發起復制操作,parallel-syncs就是用來限制在一次故障轉移之後,每次向新的主節點同時發起複製操作節點個數。如果這個值較大,  雖然一般不會阻塞主節點,但是會給網路和磁碟IO帶來開銷。

# sentinel failover-timeout

故障轉移超時時間

# sentinel auth-pass

如果sentinel監控的主節點設定了密碼,sentinel auth-pass配置通過新增主節點的密碼,防止sentinel節點對主節點無法監控。

# sentinel notification-script

在故障轉移期間,當一些警告級別的sentinel事件發生時,會觸發對應的指令碼,並向指令碼傳送相對應的事件引數。

2.4 如何監控多個主節點

sentinel monitor master1 192.168.1.201 6379 2

sentinel down-after-milliseconds master1 30000

sentinel failover-timeout master1 180000

sentinel parallel-syncs master1 1

sentinel monitor master2 192.168.1.202 6379 2

sentinel down-after-milliseconds master2 30000

sentinel failover-timeout master2 180000

sentinel parallel-syncs master2 1

2.5 部署技巧

2.4.1sentinel節點儘量不要部署在一臺物理機上

2.4.2sentinel節點至少三個而且是奇數

2.4.3 如果是同一個業務的多個主節點,可以使用一套sentinel,否則就使用多套sentinel

三Sentinel 客戶端

無論哪一種程式語言的客戶端,如果需要正確的連線Redis Sentinel,必須有Sentinel節點集合和主節點引數。

3.1Redis Sentinel 客戶端基本實現原理

實現一個Redis Sentinel客戶端的基本步驟如下:

# 遍歷sentinel節點集合獲取一個可用的sentinel節點,從任意一個sentinel節點獲取主節點資訊都是可以的

# 通過sentinel get-master-addr-by-name master-name獲取主節點資訊

# 驗證當前獲取的主節點是真正的主節點,防止故障轉移期間的主節點變化

# 保持和sentinel節點的聯絡,時刻獲取關於主節點相關的資訊

3.2Java操作Redis Sentinel


private static JedisSentinelPoolgetSentinelPool(String masterName,Set<String> sentinels) {
    if (StringUtils.isBlank(masterName) || CollectionUtils.isEmpty(sentinels)) {
        return null;
    }
    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxTotal(1024);
    config.setMaxIdle(200);
    config.setMaxWaitMillis(1000);
    return new JedisSentinelPool(masterName,sentinels,config);
}

四 Sentinel實現原理

4.1 三個定時監控任務

Redis通過三個定時任務完成對各個節點的監控:

4.1.1每隔10秒,每個Sentinel節點會向Master節點和Slave節點發送方info命令獲取最新的拓撲結構,比如:

# Replication

role:master

connected_slaves:2

slave0:ip=192.168.1.202,port=6379,state=online,offset=67874,lag=1

slave1:ip=192.168.1.203,port=6379,state=online,offset=68015,lag=0

對上述結果解析就可以找到相應的從節點。

該定時任務的作用:

# 向主節點發送info命令獲取從節點資訊,所以sentinel不需要顯示配置監控從節點

# 當有新的從節點加入,可以立刻感知出來

# 節點不可達,或者故障轉移後,可通過info命令實時更新拓撲資訊

4.1.2 每隔2秒,每一個sentinel 節點會向Redis資料節點的__sentinel__:hello 頻道上傳送該sentinel節點對於主節點的判斷以及當前sentinel節點的資訊,同時每一個sentinel節點也會訂閱該頻道

4.1.3 每隔1秒,每一個sentinel節點會向主節點,從節點,其餘sentinel節點發送一條ping命令,做一次心跳檢測,來確認這些節點當前是否可達


4.2 主觀下線和客觀下線

4.2.1主觀下線

當sentinel對主節點,從節點和其他sentinel節點發送ping命令進行心跳檢測,如果超過down-after-milliseconds沒有進行回覆,Sentinel節點就會判定該節點失敗,這個行為叫做主觀下線

4.2.2 客觀下線

當sentinel主觀下線是主節點的時候,該sentinel會通過sentinel is-master-down-by-addr,命令向其他sentinel節點詢問對主節點的判斷,當超過quorum個數的sentinel節點認為主節點確實存在問題,這時候sentinel節點會做出客觀下線的決定

4.3 領導者Sentinel節點的選舉

當sentinel節點對於主節點已經做了客觀下線,也不是立刻就進行故障轉移,在轉移還需要選舉一個leader專門用來處理故障轉移。Redis使用Raft演算法實現領導者選舉。

大致過程如下:

# 每一個線上的sentinel節點都有資格成為領導者,當它確認主節點主觀下線的時候,會向其他節點發送sentinel is-master-down-by-addr命令,要求將自己設定為leader

# 收到命令的sentinel節點,如果沒有同意過其他其他sentinel的節點is-master-down-by-addr命令,將同一該請求,否則拒絕

# 如果該sentinel發現自己的票數已經大於等於max(quorum,sentinel節點數/2+1),那麼它將成為領導者

# 如果此過程沒有選舉出leader,將進入下一次選舉

所以我們也可以這樣理解,誰最先確認主節點客觀下線,誰最有可能成為Leader.

4.4 故障轉移

4.4.1 從從節點列表選擇一個節點作為新的主節點,選擇方法如下:

# 過濾不健康的從節點

# 選擇slave-priority最高的,如果存在即返回,不存在就繼續

# 選擇複製偏移量最大的從節點,如果存在即返回,不存在就繼續

# 選擇runid最小的從節點

4.4.2 sentinelleader會對前一步選擇的從節點執行slaveof no one命令,讓其成為主節點

4.4.3sentinel leader向剩餘的從節點發送命令,讓他們成為新的主節點的從節點,複製規則和parallel-sync引數有關係

4.4.4sentinel節點集合會將原來的主節點更新為從節點,並保持對其關注,當起恢復後命令其去複製新的主節點

五Sentinel開發與運維

5.1 節點下線

臨時下線:暫時關掉節點,之後會重新啟動

永久下線:關閉之後永遠不會再使用,有時候還需要做一些清理工作,比如等

5.1.1 主節點下線

sentinel failover <master name>

5.1.2 從節點和sentinel節點

如果使用了讀寫分離,下線從節點需要保證應用方可以感知從節點的下線變化,並把讀請求路由到其他節點。

5.2 節點上線

5.2.1 新增從節點

有時候比如只有一臺節點的情況下,想使用主從,支撐故障轉移;或者使用的讀寫分離,不能支撐應用方的流量

slaveof <masterip> <masterport> 的配置,使用redis-server啟動即可,他將被 sentinel節點自動發現。

5.2.2 新增sentinel節點

當前sentinel節點數量不夠,無法達到健壯性的要求或者無法達到票數;或者之前的sentinel節點需要下線

新增配置然後正常啟動sentinel即可,被其餘的sentinel節點自動發現