1、哨兵的介紹
sentinal,中文名是哨兵
哨兵是redis集群架構中非常重要的一個組件,主要功能如下
(1)集群監控,負責監控redis master和slave進程是否正常工作
(2)消息通知,如果某個redis實例有故障,那么哨兵負責發送消息作為報警通知給管理員
(3)故障轉移,如果master node掛掉了,會自動轉移到slave node上
(4)配置中心,如果故障轉移發生了,通知client客戶端新的master地址
哨兵本身也是分布式的,作為一個哨兵集群去運行,互相協同工作
(1)故障轉移時,判斷一個master node是宕機了,需要大部分的哨兵都同意才行,涉及到了分布式選舉的問題
(2)即使部分哨兵節點掛掉了,哨兵集群還是能正常工作的,因為如果一個作為高可用機制重要組成部分的故障轉移系統本身是單點的,那就很坑爹了
目前采用的是sentinal 2版本,sentinal 2相對於sentinal 1來說,重寫了很多代碼,主要是讓故障轉移的機制和算法變得更加健壯和簡單
2、哨兵的核心知識
(1)哨兵至少需要3個實例,來保證自己的健壯性
(2)哨兵 + redis主從的部署架構,是不會保證數據零丟失的,只能保證redis集群的高可用性
(3)對於哨兵 + redis主從這種復雜的部署架構,盡量在測試環境和生產環境,都進行充足的測試和演練
3、為什么redis哨兵集群只有2個節點無法正常工作?
哨兵集群必須部署2個以上節點
如果哨兵集群僅僅部署了個2個哨兵實例,quorum=1
+----+ +----+
| M1 |---------| R1 |
| S1 | | S2 |
+----+ +----+
Configuration: quorum = 1
master宕機,s1和s2中只要有1個哨兵認為master宕機就可以還行切換,同時s1和s2中會選舉出一個哨兵來執行故障轉移
同時這個時候,需要majority,也就是大多數哨兵都是運行的,2個哨兵的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),2個哨兵都運行着,就可以允許執行故障轉移
但是如果整個M1和S1運行的機器宕機了,那么哨兵只有1個了,此時就沒有majority來允許執行故障轉移,雖然另外一台機器還有一個R1,但是故障轉移不會執行
4、經典的3節點哨兵集群
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
Configuration: quorum = 2,majority
如果M1所在機器宕機了,那么三個哨兵還剩下2個,S2和S3可以一致認為master宕機,然后選舉出一個來執行故障轉移
同時3個哨兵的majority是2,所以還剩下的2個哨兵運行着,就可以允許執行故障轉移
1、兩種數據丟失的情況
2、解決異步復制和腦裂導致的數據丟失
------------------------------------------------------------------
1、兩種數據丟失的情況
主備切換的過程,可能會導致數據丟失
(1)異步復制導致的數據丟失
因為master -> slave的復制是異步的,所以可能有部分數據還沒復制到slave,master就宕機了,此時這些部分數據就丟失了
(2)腦裂導致的數據丟失
腦裂,也就是說,某個master所在機器突然脫離了正常的網絡,跟其他slave機器不能連接,但是實際上master還運行着
此時哨兵可能就會認為master宕機了,然后開啟選舉,將其他slave切換成了master
這個時候,集群里就會有兩個master,也就是所謂的腦裂
此時雖然某個slave被切換成了master,但是可能client還沒來得及切換到新的master,還繼續寫向舊master的數據可能也丟失了
因此舊master再次恢復的時候,會被作為一個slave掛到新的master上去,自己的數據會清空,重新從新的master復制數據
------------------------------------------------------------------
2、解決異步復制和腦裂導致的數據丟失
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1個slave,數據復制和同步的延遲不能超過10秒
如果說一旦所有的slave,數據復制和同步的延遲都超過了10秒鍾,那么這個時候,master就不會再接收任何請求了
上面兩個配置可以減少異步復制和腦裂導致的數據丟失
(1)減少異步復制的數據丟失
有了min-slaves-max-lag這個配置,就可以確保說,一旦slave復制數據和ack延時太長,就認為可能master宕機后損失的數據太多了,那么就拒絕寫請求,這樣可以把master宕機時由於部分數據未同步到slave導致的數據丟失降低的可控范圍內
(2)減少腦裂的數據丟失
如果一個master出現了腦裂,跟其他slave丟了連接,那么上面兩個配置可以確保說,如果不能繼續給指定數量的slave發送數據,而且slave超過10秒沒有給自己ack消息,那么就直接拒絕客戶端的寫請求
這樣腦裂后的舊master就不會接受client的新數據,也就避免了數據丟失
上面的配置就確保了,如果跟任何一個slave丟了連接,在10秒后發現沒有slave給自己ack,那么就拒絕新的寫請求
因此在腦裂場景下,最多就丟失10秒的數據
1、sdown和odown轉換機制
sdown和odown兩種失敗狀態
sdown是主觀宕機,就一個哨兵如果自己覺得一個master宕機了,那么就是主觀宕機
odown是客觀宕機,如果quorum數量的哨兵都覺得一個master宕機了,那么就是客觀宕機
sdown達成的條件很簡單,如果一個哨兵ping一個master,超過了is-master-down-after-milliseconds指定的毫秒數之后,就主觀認為master宕機
sdown到odown轉換的條件很簡單,如果一個哨兵在指定時間內,收到了quorum指定數量的其他哨兵也認為那個master是sdown了,那么就認為是odown了,客觀認為master宕機
2、哨兵集群的自動發現機制
哨兵互相之間的發現,是通過redis的pub/sub系統實現的,每個哨兵都會往__sentinel__:hello這個channel里發送一個消息,這時候所有其他哨兵都可以消費到這個消息,並感知到其他的哨兵的存在
每隔兩秒鍾,每個哨兵都會往自己監控的某個master+slaves對應的__sentinel__:hello channel里發送一個消息,內容是自己的host、ip和runid還有對這個master的監控配置
每個哨兵也會去監聽自己監控的每個master+slaves對應的__sentinel__:hello channel,然后去感知到同樣在監聽這個master+slaves的其他哨兵的存在
每個哨兵還會跟其他哨兵交換對master的監控配置,互相進行監控配置的同步
3、slave配置的自動糾正
哨兵會負責自動糾正slave的一些配置,比如slave如果要成為潛在的master候選人,哨兵會確保slave在復制現有master的數據; 如果slave連接到了一個錯誤的master上,比如故障轉移之后,那么哨兵會確保它們連接到正確的master上
4、slave->master選舉算法
如果一個master被認為odown了,而且majority哨兵都允許了主備切換,那么某個哨兵就會執行主備切換操作,此時首先要選舉一個slave來
會考慮slave的一些信息
(1)跟master斷開連接的時長
(2)slave優先級
(3)復制offset
(4)run id
如果一個slave跟master斷開連接已經超過了down-after-milliseconds的10倍,外加master宕機的時長,那么slave就被認為不適合選舉為master
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
接下來會對slave進行排序
(1)按照slave優先級進行排序,slave priority越低,優先級就越高
(2)如果slave priority相同,那么看replica offset,哪個slave復制了越多的數據,offset越靠后,優先級就越高
(3)如果上面兩個條件都相同,那么選擇一個run id比較小的那個slave
5、quorum和majority
每次一個哨兵要做主備切換,首先需要quorum數量的哨兵認為odown,然后選舉出一個哨兵來做切換,這個哨兵還得得到majority哨兵的授權,才能正式執行切換
如果quorum < majority,比如5個哨兵,majority就是3,quorum設置為2,那么就3個哨兵授權就可以執行切換
但是如果quorum >= majority,那么必須quorum數量的哨兵都授權,比如5個哨兵,quorum是5,那么必須5個哨兵都同意授權,才能執行切換
6、configuration epoch
哨兵會對一套redis master+slave進行監控,有相應的監控的配置
執行切換的那個哨兵,會從要切換到的新master(salve->master)那里得到一個configuration epoch,這就是一個version號,每次切換的version號都必須是唯一的
如果第一個選舉出的哨兵切換失敗了,那么其他哨兵,會等待failover-timeout時間,然后接替繼續執行切換,此時會重新獲取一個新的configuration epoch,作為新的version號
7、configuraiton傳播
哨兵完成切換之后,會在自己本地更新生成最新的master配置,然后同步給其他的哨兵,就是通過之前說的pub/sub消息機制
這里之前的version號就很重要了,因為各種消息都是通過一個channel去發布和監聽的,所以一個哨兵完成一次新的切換之后,新的master配置是跟着新的version號的
其他的哨兵都是根據版本號的大小來更新自己的master配置的
====================================================================================================
動手實操,練習如何操作部署哨兵集群,如何基於哨兵進行故障轉移,還有一些企業級的配置方案
1、哨兵的配置文件
sentinel.conf
最小的配置
每一個哨兵都可以去監控多個maser-slaves的主從架構
因為可能你的公司里,為不同的項目,部署了多個master-slaves的redis主從集群
相同的一套哨兵集群,就可以去監控不同的多個redis主從集群
你自己給每個redis主從集群分配一個邏輯的名稱
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
sentinel monitor mymaster 127.0.0.1 6379
類似這種配置,來指定對一個master的監控,給監控的master指定的一個名稱,因為后面分布式集群架構里會講解,可以配置多個master做數據拆分
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
上面的三個配置,都是針對某個監控的master配置的,給其指定上面分配的名稱即可
上面這段配置,就監控了兩個master node
這是最小的哨兵配置,如果發生了master-slave故障轉移,或者新的哨兵進程加入哨兵集群,那么哨兵會自動更新自己的配置文件
sentinel monitor master-group-name hostname port quorum
quorum的解釋如下:
(1)至少多少個哨兵要一致同意,master進程掛掉了,或者slave進程掛掉了,或者要啟動一個故障轉移操作
(2)quorum是用來識別故障的,真正執行故障轉移的時候,還是要在哨兵集群執行選舉,選舉一個哨兵進程出來執行故障轉移操作
(3)假設有5個哨兵,quorum設置了2,那么如果5個哨兵中的2個都認為master掛掉了; 2個哨兵中的一個就會做一個選舉,選舉一個哨兵出來,執行故障轉移; 如果5個哨兵中有3個哨兵都是運行的,那么故障轉移就會被允許執行
down-after-milliseconds,超過多少毫秒跟一個redis實例斷了連接,哨兵就可能認為這個redis實例掛了
parallel-syncs,新的master別切換之后,同時有多少個slave被切換到去連接新master,重新做同步,數字越低,花費的時間越多
假設你的redis是1個master,4個slave
然后master宕機了,4個slave中有1個切換成了master,剩下3個slave就要掛到新的master上面去
這個時候,如果parallel-syncs是1,那么3個slave,一個一個地掛接到新的master上面去,1個掛接完,而且從新的master sync完數據之后,再掛接下一個
如果parallel-syncs是3,那么一次性就會把所有slave掛接到新的master上去
failover-timeout,執行故障轉移的timeout超時時長
2、在eshop-cache03上再部署一個redis
只要安裝redis就可以了,不需要去部署redis實例的啟動
wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
tar -xzvf tcl8.6.1-src.tar.gz
cd /usr/local/tcl8.6.1/unix/
./configure
make && make install
使用redis-3.2.8.tar.gz(截止2017年4月的最新穩定版)
tar -zxvf redis-3.2.8.tar.gz
cd redis-3.2.8
make && make test
make install
2、正式的配置
哨兵默認用26379端口,默認不能跟其他機器在指定端口連通,只能在本地訪問
mkdir /etc/sentinal
mkdir -p /var/sentinal/5000
/etc/sentinel/5000.conf
port 5000
bind 192.168.31.187
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.187 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
port 5000
bind 192.168.31.19
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.187 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
port 5000
bind 192.168.31.227
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.187 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
3、啟動哨兵進程
在eshop-cache01、eshop-cache02、eshop-cache03三台機器上,分別啟動三個哨兵進程,組成一個集群,觀察一下日志的輸出
redis-sentinel /etc/sentinal/5000.conf
redis-server /etc/sentinal/5000.conf --sentinel
日志里會顯示出來,每個哨兵都能去監控到對應的redis master,並能夠自動發現對應的slave
哨兵之間,互相會自動進行發現,用的就是之前說的pub/sub,消息發布和訂閱channel消息系統和機制
4、檢查哨兵狀態
redis-cli -h 192.168.31.187 -p 5000
sentinel master mymaster
SENTINEL slaves mymaster
SENTINEL sentinels mymaster
SENTINEL get-master-addr-by-name mymaster
========================================具體操作=======================================================================
在redis機器上創建兩個文件夾
創建一個這文件夾:
mkdir /var/sentinal/5000
mkdir /etc/sentinal/
配置一個5000.conf文件
/etc/sentinal/5000.conf
這個配置文件的初始位置在redis下載安裝后帶的,可以在這個位置找到
redis-sentinel /etc/sentinal/5000.conf
------------------------------准備第三台機器-------------------------
目前機器1,機器2,機器3都起來了,發現沒能相互發現。
------------------------------------------------------------------------------------
5000.conf最終改為
protected-mode no
port 26379
dir /var/sentinal/5000
daemonize yes
sentinel monitor mymaster 192.168.31.20 6379 2
sentinel down-after-milliseconds mymaster 10000
sentinel failover-timeout mymaster 60000
改完文件,一個一個發到別的服務器
scp 5000.conf root@192.168.31.244:/etc/sentinal/5000.conf
。。。。
啟動哨兵
redis-sentinel /etc/sentinal/5000.conf --sentinel 后面的-- 是后台啟動,測試就不要后台啟動了,影響調試
ps -ef|grep redis
看一下進程
啟動成功了,查看一下各自的500的conf發現都有自己的生成myid
====================很遺憾,嘗試了兩天都還沒進展,挑戰失敗。====================
目前遇到的問題就是,日志只有一條基本信息,看不到什么從節點的連接情況,嘗試把主節點停掉,從節點不會自動切換主節點。
------------------------------------------------------------2022.1.4找到突破點 ,再來改改----------------------------------------------------------------------------------------------------------------
機器31.20(主)
port 5000
bind 192.168.31.20
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.20 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster redis-pass
機器31.186(從)
port 5000
bind 192.168.31.186
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.20 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster redis-pass
機器31.244(從)
port 5000
bind 192.168.31.244
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.31.20 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster redis-pass
========================本次更新哨兵連接密碼======================================
本來配置這個來着 logfile:./sentinel.log,輸入后報錯,刪除了。
三個集群的情況
4、檢查哨兵狀態
redis-cli -h 192.168.31.20 -p 5000
sentinel master mymaster
SENTINEL slaves mymaster
SENTINEL sentinels mymaster
SENTINEL get-master-addr-by-name mymaster
都正常,發現kill-9 主節點后,從節點自動切換到主節點,然后新的主節點寫數據,從節點沒更新。。。。
========================2022年2月3日,繼續更新,我就不信改不對==============================================================
哨兵端口一般都是26379
帶注釋的說明文件配置:
#不限制ip bind 0.0.0.0 #后台運行 daemonize yes # 配置監聽的主服務器,my是名稱,目標ip,目標端口,2代表兩個認為不可用才會切換 sentinel monitor mymaster 192.168.31.20 6379 2 #sentinel 密碼, 服務名稱 redis的連接密碼 sentinel auth-pass mymaster 123456 sentinel down-after-milliseconds mymaster 5000 #如果該事件內沒有完成failover操作,認為本地failover失敗 sentinel failover-timeout mymaster 30000
當前配置如下:
日志文件位置: /var/sentinal/5000 文件位置:/etc/sentinal/5000.conf
修改如下:
日志log文件和conf配置文件名都修改了,值也進行修改
日志文件位置:
port 26379
bind 0.0.0.0
daemonize yes
pidfile "/var/sentinal/redis-sentinel.pid"
logfile "/var/sentinal/sentinel_26379.log"
sentinel monitor mymaster 192.168.31.20 6379 2
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 30000
將etc/sentinal/26379.conf文件發送到別的地址
scp 26379.conf root@192.168.31.244:/etc/sentinal/26379.conf scp 26379.conf root@192.168.31.186:/etc/sentinal/26379.conf
redis-sentinel /etc/sentinal/26379.conf --sentinel
剛剛操作一遍,把主節點停掉,等了一會修改數據,主從讀寫可以正常使用!