Redis 高可用之 Sentinel

微信公眾號:運維開發(fā)故事,作者:鄭哥

圖片

在 redis3.0 以前的版本要實現(xiàn)集群一般是借助哨兵 sentinel 工具來監(jiān)控 master 節(jié)點的狀態(tài),如果 master 節(jié)點異常,則會做主從切換,將某一臺 slave 作為 master,哨兵的配置略微復(fù)雜,并且性能和高可用性等各方面表現(xiàn)一般,特別是在主從切換的瞬間存在訪問瞬斷的情況,而且哨兵模式只有一個主節(jié)點對外提供服務(wù),沒法支持很高的并發(fā),且單個主節(jié)點內(nèi)存也不宜設(shè)置得過大,否則會導(dǎo)致持久化文件過大,影響數(shù)據(jù)恢復(fù)或主從同步的效率。

Sentinel 初始化

Sentinel(哨兵)是 Redis 高可用(high availability) 解決方案,由一個或者多個 Sentinel 實例(instance)組成的 Sentinel 系統(tǒng)(system)可以監(jiān)視一個或者多個 Redis 主服務(wù)器和其跟隨的從服務(wù)器,并且在被監(jiān)視的主服務(wù)進(jìn)入下線狀態(tài)時,自動進(jìn)行將當(dāng)前主服務(wù)器的從服務(wù)器其中一個升級為主服務(wù)器,然后將下線的主服務(wù)器設(shè)置為新主服務(wù)器的從節(jié)點。

Sentinel 本身我們可以理解為一個特殊的 Redis 服務(wù)器, 它也可以通過 redis-server xxx.conf --sentinel啟動。

下面是我們實驗環(huán)境的一個 Sentinel 服務(wù)器和 Redis 服務(wù)器列表(由于實驗都在本機進(jìn)行,我們采用端口的方式來區(qū)分多個服務(wù)),服務(wù)和端口大致如下:

IP端口集群
127.0.0.16379Master
127.0.0.16380Slave
127.0.0.16381Slave
127.0.0.126379Sentinel
127.0.0.126380Sentinel
127.0.0.126381Sentinel

首先我們找到 Redis 的配置文件目錄,修改 redis-sentinel.conf文件中的以下參數(shù):

# sentinel 端口
port 26381
# 后臺運行
daemonize yes
# 監(jiān)控主服務(wù)器和有一個 slave 節(jié)點
sentinel monitor mymaster 127.0.0.1 6379 2

Sentinel 啟動命令如下:

redis-server redis-sentinel-26379.conf --sentinel
redis-server redis-sentinel-26380.conf --sentinel
redis-server redis-sentinel-26381.conf --sentinel

登錄到 Sentinel 節(jié)點, 查詢集群狀態(tài), 使用 info命令即可圖片sentinel 服務(wù)和其他 redis 服務(wù)節(jié)點啟動區(qū)別,就是在啟動的過程中,不會加載 RDB 或者 AOF 來還原數(shù)據(jù)。

Sentinel 和 Redis 服務(wù)之間的通訊

  • _命令連接_,建立一個鏈接接收主/從服務(wù)器的回復(fù) (默認(rèn) 10 秒一次發(fā)送請求 info 信息獲取節(jié)點狀態(tài),故障轉(zhuǎn)移的時候會變?yōu)?1 秒一次。并且每一秒向服務(wù)器節(jié)點發(fā)一個 PING 命令判斷服務(wù)是否在線

圖片

image.png

  • 訂閱鏈接,用于訂閱主服務(wù)器的 __sentinel__:hello 頻道

我們先驗證一下在主節(jié)點上查詢,執(zhí)行 SUBSCRIBE __sentinel__:hello圖片主節(jié)點服務(wù)上的同步信息,我們可以通過 INFO 命令來查詢圖片從節(jié)點服務(wù)器上通過 INFO 命令查詢同步信息圖片

Sentinel 之間通訊

  • 對于監(jiān)視同一個主/從服務(wù)器的多個 Sentinel 節(jié)點,他們會以每兩秒一次的頻率,向被監(jiān)視的服務(wù)器的 __sentinel__:hello 頻道發(fā)送消息來宣告自己存在。

  • Sentinel 之間不會創(chuàng)建訂閱鏈接,通過命令通訊。因為已經(jīng)可以通過主/從服務(wù)器獲取未知的 Sentinel 服務(wù)節(jié)點。

Sentinel 獲取 Redis 節(jié)點列表

** Sentinel 會默認(rèn) 10 秒一次向主服務(wù)器信息**,通過**發(fā)送 info 命令**,的回復(fù)來獲取當(dāng)前主服務(wù)器的信息。

# Server
run_id:5e4d6e3ee147ff231d540ae2add485e906944f2a

...

# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=2712947,lag=0
slave1:ip=127.0.0.1,port=6380,state=online,offset=2712947,lag=0
master_replid:f2163cc41b43c20998a54c14647ba5b106dc4677
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2713213
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1664638
repl_backlog_histlen:1048576

....

通過分析主服務(wù)器的 info 命令可以獲取到以下兩方面的信息:

  1. 關(guān)于服務(wù)器本身的信息,包括 run_id 記錄服務(wù)器運行的 id, 以及服務(wù)器 role 角色等。

  2. 另外一方面就是獲取主服務(wù)器下面的所有從服務(wù)器信息,比如: slave0:ip=127.0.0.1,port=6381,state=online,offset=2712947,lag=0這樣就不需要我們在 conf 文件中配置從服務(wù)器的信息,Sentinel 可以自動發(fā)現(xiàn)。

當(dāng) Sentinel 從主服務(wù)器獲取到從服務(wù)器信息過后,也會 10 秒鐘向從服務(wù)器發(fā)送 INFO 命令來獲取從服務(wù)器信息 我們可以執(zhí)行命令 redis-cli -h 127.0.0.1 -p 6380 info 得到以下信息






# Server 
run_id:7ef635af0d3e0b1d60d2776eba0a15883db06245

...

# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:2779874
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:f2163cc41b43c20998a54c14647ba5b106dc4677
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2779874
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1731299
repl_backlog_histlen:1048576

...

我們從結(jié)果中可以得到以下信息:

  1. 服務(wù)器的運行 Id run_id

  2. 服務(wù)器的角色 role

  3. 主服務(wù)器的信息 master_host, master_port

  4. 主從服務(wù)器的連接狀態(tài) master_link_status

  5. 從服務(wù)器的優(yōu)先級 slave_priority

  6. 從服務(wù)器的復(fù)制偏移量 slave_repl_offset

服務(wù)下線

主觀下線:一臺 sentinel 判斷下線 客觀下線:主觀下線后會詢問其他的 sentinel 節(jié)點判斷是否該主節(jié)點下線,如果是真的下線了,那么就是客觀下線。圖片

判斷下線的方式

sentinel 配置文件中 down-after-millseconds 選項制定了 sentinel 實例進(jìn)入主觀下線所需的時間;如果一個實例在 down-after-millseconds毫秒內(nèi),連續(xù)向 Sentinel 返回?zé)o效回復(fù),那么 Sentinel 會修改這個實例所對應(yīng)的實例結(jié)構(gòu),在結(jié)構(gòu)的 flags 屬性中打開 SIR_S_DOWN 標(biāo)示,來表示這個實例主觀下線。當(dāng)超過一半的哨兵節(jié)監(jiān)測到一個redis 節(jié)點下線后此刻在該集群中該節(jié)點才算真正被判斷為下線,也叫客觀下線

選舉領(lǐng)頭 sentinel

當(dāng)發(fā)生 master 節(jié)點客觀下線后,會進(jìn)行 sentinel 選舉,進(jìn)行選舉出領(lǐng)頭 sentinel 對 redis sentinel 集群做故障轉(zhuǎn)移。領(lǐng)頭 sentinel 選舉規(guī)則:

  1. 所有在線的 sentinel 都具有選舉資格。

  2. 每次選舉后,不管是否選舉成功,sentinel 配置紀(jì)元(configuration epoch)都會自增一次

  3. 每個配置紀(jì)元里面都有一次將某個 sentinel 設(shè)置為局部領(lǐng)頭 sentinel 的機會,且局部領(lǐng)頭 sentinel 一旦設(shè)置當(dāng)前配置紀(jì)元里面不可修改

  4. 每個發(fā)現(xiàn)主服務(wù)器客觀下線的 sentinel 都會要求其他的 sentinel 將自己設(shè)置為局部的 領(lǐng)頭 sentinel

  5. sentinel 局部領(lǐng)頭 sentinel 的規(guī)則是先到先的,最先向目標(biāo) sentinel 發(fā)送設(shè)置要求的 sentinel 先設(shè)置成功,之后的都會被拒絕

  6. 如果某個 sentinel 被半數(shù)以上的 sentinel 設(shè)置成了局部領(lǐng)頭 sentinel ,那么這個 sentinel 就成為領(lǐng)頭 sentinel

  7. 因為領(lǐng)頭 sentinel 產(chǎn)生需要半數(shù)的 sentinel 的支持,并且每個配置紀(jì)元里面只能設(shè)置一次 領(lǐng)頭 sentinel ,所以只會出現(xiàn)一個領(lǐng)頭 sentinel

  8. 如果在指定的時間內(nèi)沒有產(chǎn)生領(lǐng)頭 sentinel 那么就會進(jìn)行再次選舉,直到選出領(lǐng)頭 sentinel 為止。

故障轉(zhuǎn)移

故障轉(zhuǎn)移分為三個步驟:

  1. 在已經(jīng)下線的主服務(wù)器下的所有服務(wù)器里中,選擇一個從服務(wù)器,將器作為主服務(wù)器。

  2. 讓已經(jīng)下線的主服務(wù)器下的所有從服務(wù)器復(fù)制新的主服務(wù)器。

  3. 將已經(jīng)下線的主服務(wù)器設(shè)置為新主服務(wù)器的從服務(wù)器,當(dāng)這個舊的主服務(wù)器重新上線后它就會成為新的主服務(wù)器的從服務(wù)器。

選擇新主服務(wù)器

對從服務(wù)器進(jìn)行過濾

  1. 刪除處于下線的從服務(wù)器,保證都是正常在線

  2. 刪除列表中所有 5 秒沒有回復(fù)過 sentinle leader 的 info 命令的服務(wù)器,可以保證列表中剩余的從服務(wù)器通訊正常

  3. 保證從服務(wù)器的數(shù)據(jù)是最新的,主要是刪除與主服務(wù)器斷開鏈接超過 down-after-millseconds * 10 毫秒的服務(wù)器。保證沒有過早的斷開鏈接

  4. 最后按照上面的篩選過后,進(jìn)行排序,選擇其中優(yōu)先級最高的。

    1. 如果存在多個相同優(yōu)先級的,考慮偏移量(slave_repl_offset)最大的從服務(wù)器,因為偏移量最大說明保存的數(shù)據(jù)是最新的
  1. 如果還是存在相同的偏移量的從服務(wù)器,那么就選擇運行 id(run_id)最小的從服務(wù)器

圖片

發(fā)生故障轉(zhuǎn)移后 Server2 升級為主服務(wù)器

修改從服務(wù)器的復(fù)制目標(biāo)

當(dāng)新的主服務(wù)器出現(xiàn)后 ,領(lǐng)頭的 Sentinel 會讓其他的服務(wù)器節(jié)點,去復(fù)制新的主節(jié)點的數(shù)據(jù)可以通過向從服務(wù)器發(fā)送 saveof 命令來實現(xiàn)。圖片

將舊的主服務(wù)器變成從服務(wù)器

故障轉(zhuǎn)移的最后操作,就是將已經(jīng)下線的的主服務(wù)器設(shè)置為新的主服務(wù)的從服務(wù)器。圖片

公眾號:運維開發(fā)故事

github:https://github.com/orgs/sunsharing-note/dashboard


作者:鄭哥 運維開發(fā)故事


歡迎關(guān)注:運維開發(fā)故事