玩轉Redis高可用 - 哨兵(Sentinel)模式

目錄

一、前言

二、何爲哨兵模式

三、Redis環境搭建

1、安裝gcc依賴

2、下載redis安裝包

四、哨兵模式設置

五、數據同步、高可用方案驗證

1、數據同步

2、高可用驗證

六、結語


一、前言 

本人所負責的團隊裏也廣泛使用Redis,但是集羣模式也有很多種,有三主三從,有一主兩從三哨兵等。具體部署方式根據業務系統的重要程度,但記住哨兵儘量是奇數個,因爲要避免發生腦裂。
三主三從這個確實可以最完整的保證數據的完整性,但是所需要的服務器資源也是最多的。在一般情況,統籌兼顧數據完整性和方案經濟性,一般最優解是採用一主兩從三哨兵的模式。本着總結是爲了更好的運用,這裏就大致整理一下之前項目中使用的Redis哨兵模式(Sentinel)的搭建方式,並演示一下數據如何同步,故障如何自動轉移。
 

二、何爲哨兵模式

首先, 哨兵模式是一種特殊的模式,它是Redis高可用的一種實現方案。首先哨兵是一個獨立的進程, 可以實現對Redis實例的監控、通知、自動故障轉移。具體如下:
 
a、監控(Monitoring): 哨兵(sentinel) 會不斷地檢查你的Master和Slave是否運作正常。
b、提醒(Notification):當被監控的某個Redis出現問題時, 哨兵(sentinel) 可以通過 API 向管理員或者其他應用程序發送通知。
c、自動故障遷移(Automatic failover):當一個Master不能正常工作時,哨兵(sentinel) 會開始一次自動故障遷移操作,它會將失效Master的其中一個Slave升級爲新的Master, 並讓失效Master的其他Slave改爲複製新的Master; 當客戶端試圖連接失效的Master時,集羣也會向客戶端返回新Master的地址,使得集羣可以使用Master代替失效Master。
 
這裏先發個拓撲圖可能會更加容易理解。
 
實際上,每個哨兵節點每秒通過ping去進行心跳監測(包括所有redis實例和sentinel同伴),並根據回覆判斷節點是否在線。
 
如果某個sentinel線程發現主庫沒有在給定時間( down-after-milliseconds)內響應這個PING,則這個sentinel線程認爲主庫是不可用的,這種情況叫“主觀失效”(即SDOWN);這種情況一般不會引起馬上的故障自動轉移,但是當多個sentinel線程確實發現主庫是不可用並超過sentinel.conf裏面的配置項sentinel monitor mymaster {#ip} {#port} {#number}中的#number時候(這裏實際上採用了流言協議),一般其餘sentinel線程會通過RAFT算法推舉領導的sentinel線程負責主庫的客觀下線並同時負責故障自動轉移,這種情況叫“客觀失效”(即ODOWN)
 
*** 流言協議【Gossip Protocol】,具體的流言協議請參考搜狐的一篇文章 https://www.sohu.com/a/302002994_467784

 

三、Redis環境搭建

 

1、安裝gcc依賴

gcc是什麼?gcc實際上就是linux下面的多語言編譯器(以前一開始只支持C),所以它的全稱也叫GNU Compiler Collections。例如你下載個Redis等都是需要進行編譯安裝。廢話不多說,先開始安裝吧。
#先檢查你的centos之前有沒有安裝過gcc。如有有以下echo即證明已安裝。
 
[root@centos7a local]# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)

#如果沒有,就通過yum安裝吧,具體命令如下:
yum install gcc

 

2、下載redis安裝包

1、這裏以5.0.8爲例,首先下載redis包 
[root@centos7a local]# wget http://download.redis.io/releases/redis-5.0.8.tar.gz
--2020-06-05 20:48:59--  http://download.redis.io/releases/redis-5.0.8.tar.gz
Resolving download.redis.io (download.redis.io)... 109.74.203.151
Connecting to download.redis.io (download.redis.io)|109.74.203.151|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1985757 (1.9M) [application/x-gzip]
Saving to: ‘redis-5.0.8.tar.gz’
100%[===================================================================================================================================================>] 1,985,757   30.2KB/s   in 88s
2020-06-05 20:50:27 (22.1 KB/s) - ‘redis-5.0.8.tar.gz’ saved [1985757/1985757]
2、解壓
[root@centos7a local]# tar -zxvf redis-5.0.8.tar.gz
 
#注意 
如果gcc版本過低,在安裝redis 6.0.0以上會報這類錯誤  => make[1]: *** [server.o] Error 1。一般的解決方案:1)升級gcc版本;2)安裝低版本的redis;
博主懶得升級gcc,因此選擇後者,直接安裝5.0.8版本,一路通關無障礙。
3、編譯安裝
#1、進入安裝目錄
[root@centos7a local]# cd redis-5.0.8/   
[root@centos7a redis-5.0.8]# pwd
/usr/local/redis-5.0.8
 
#2、開始編譯安裝
[root@centos7a redis-5.0.8]# make MALLOC=libc
cd src && make all
make[1]: Entering directory `/usr/local/redis-5.0.8/src'
    CC Makefile.dep
.....
.....
    INSTALL redis-check-aof
Hint: It's a good idea to run 'make test' ;)
make[1]: Leaving directory `/usr/local/redis-5.0.8/src'
4、修改配置 (/usr/local/redis-5.0.8/redis.conf)
#1、redis默認不是以線程守護的方式運行的,如需要調整至線程守護的方式,請把
daemonize no  =>  daemonize yes
 
#2、把默認端口6379改爲其他
port 6379   => port 9500
 
#3、bind會限制能夠訪問redis的地址,默認(127.0.0.1)是指本地才能訪問。如果要放開redis,如要搭建redis集羣的話,要把bind註釋掉;同時要把protected-mode從yes改爲no
#bind 127.0.0.1
protected-mode yes  => protected-mode no
 
#4、把PID文件名改成跟修改後的PORT一致
pidfile /var/run/redis_9500.pid
 
#5、設定日誌文件路徑
logfile "/var/run/redis/redis.log"
5、通過systemd進行服務啓停管理
#1、 在/lib/systemd/system/目錄下新建文件redis.service,並加入以下內容並保存
[Unit]
Description=Redis
After=network.target
 
 
[Service]
ExecStart=/usr/local/redis-5.0.8/src/redis-server /usr/local/redis-5.0.8/redis.conf  --daemonize no
ExecStop=/usr/local/redis-5.0.8/src/redis-cli -h 127.0.0.1 -p 9500 shutdown
 
 
[Install]
WantedBy=multi-user.target
 
#2、刷新配置
systemctl daemon-reload
 
#3、直接就可以使用systemctl進行start/stop/restart
systemctl start redis.service     //啓動
systemctl restart redis.service   //重啓
systemctl stop redis.service      //關停
systemctl enable redis.service    //設置成開機啓動
 
只要在日誌文件中看到如下日誌,那就代表redis已經啓動了。
 
 
6、測試redis數據庫
# 1、從下面的命令可以看到Redis已經啓動並提供服務
[root@centos7a system]# netstat -tunlp|grep redis
tcp        0      0 0.0.0.0:9500            0.0.0.0:*               LISTEN      10331/redis-server
tcp6       0      0 :::9500                 :::*                    LISTEN      10331/redis-server
 
# 2、對Redis進行一系列操作
[root@centos7a src]# ./redis-cli -h 127.0.0.1 -p 9500
127.0.0.1:9500> SET K1 LIWENJIE
OK
127.0.0.1:9500> KEYS *
1) "K1"
2) "K3"
3) "K2"
127.0.0.1:9500> DEL K1
(integer) 1
127.0.0.1:9500> EXPIRE K2 1000
(integer) 1
127.0.0.1:9500> TTL K2
(integer) 997
127.0.0.1:9500> PERSIST K2
(integer) 1
127.0.0.1:9500> TTL K2
(integer) -1
 
7、從以上6個步驟來看,一臺Redis的搭建是不是特別容易就搞定呢?接下來的就是重複上面的步驟搭建另外兩個Redis。
 

四、哨兵模式設置

1、這裏我們採用的一主兩從三哨兵的模式進行介紹,下面列出相應的服務器信息。
 
實例
IP
端口
備註
Redis(主)
192.168.31.168
9500
 
Redis(從)
192.168.31.181
9501
 
Redis(從)
192.168.31.129
9502
 
Sentinel(1)
192.168.31.168
26379
默認端口
Sentinel(2)
192.168.31.181
26379
默認端口
Sentinel(3)
192.168.31.129
26379
默認端口
2、首先,修改每個redis服務器對應的redis.conf文件(如下)。
# 1、 首先,把IP綁定改爲綁定對應服務器內網IP. (三個redis實例的都要修改)
 
# 2、因爲這裏是以192.168.31.168這臺作爲主庫,因此只需要修改181和129這兩臺從庫的以下配置項(只需要修改兩個從redis實例)
# 這裏請注意,5.0版本之前是使用slaveof,5.0版本之後的配置使用replicaof,但是因爲向下兼容的原則,就算你在5.0的版本中使用slaveof也不會有問題,但一般建議有新的就用新的吧,否則某天如果突然不支持舊的slaveof就GG了。
replicaof 192.168.31.168 9500
 
3、修改每個sentinel.conf(如下)
[root@centos7a redis-5.0.8]# grep -Ev "^$|#" sentinel.conf    #先grep出來展示有什麼屬性項
port 26379       
daemonize no                                          # 是否後臺運行
pidfile /var/run/redis-sentinel.pid              # 運行時的pid文件
logfile ""                                                    # sentinel日誌文件
dir /tmp                                                     # 工作目錄
sentinel monitor mymaster 127.0.0.1 6379 2           # 這裏定義主庫的IP和端口,還有最後的2表示要達到2臺sentinel認同才認爲主庫已經掛掉(即客觀失效),後面科普
sentinel down-after-milliseconds mymaster 30000  # 主庫在30000毫秒(即30秒)內沒有反應就認爲主庫掛掉(即主觀失效)
sentinel parallel-syncs mymaster 1                          # 若新主庫當選後,允許最大可以同時從新主庫同步數據的從庫數
sentinel failover-timeout mymaster 180000             # 若在指定時間(即180000毫秒,即180秒)內沒有實現故障轉移,則會自動再發起一次
sentinel deny-scripts-reconfig yes           

     

# 1、修改日誌文件
logfile "/var/log/sentinel.log"
 
# 2、修改主庫的IP和端口
sentinel monitor mymaster 192.168.31.168 9500 2
 
# 3、設置成後臺運行
daemonize yes
 
# 4、其他如無特別就不用修改
 
4、把redis-sentinel設置成systemd啓動
#1、 在/lib/systemd/system/目錄下新建文件redis-sentinel.service,並加入以下內容並保存
 
[Unit]
Description=Redis
After=network.target
 
 
[Service]
ExecStart=/usr/local/redis-5.0.8/src/redis-sentinel /usr/local/redis-5.0.8/sentinel.conf –sentinel
ExecStop=/usr/local/redis-5.0.8/src/redis-cli -p 26379 shutdown
 
 
[Install]
WantedBy=multi-user.target
 
 
#2、刷新配置
systemctl daemon-reload
5、使用以下命令啓動Redis和Sentinel,具體順序爲:Redis(主)-> Redis(從)->Redis(從)->Sentinel(1)->Sentinel(2)->Sentinel(3)
Redis:systemctl start redis.service
Sentinel:./redis-sentinel /usr/local/redis-5.0.8/sentinel.conf
 
啓動完後,通過以下命令可以確認主從關係已經確立。
[root@centos7a src]# ./redis-cli -h 192.168.31.168 -p 9500
192.168.31.168:9500> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.31.181,port=9501,state=online,offset=2235966,lag=1
slave1:ip=192.168.31.129,port=9502,state=online,offset=2235966,lag=1
master_replid:1df20ecc0df92307ef811e9bd81cc09e131725c7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2236538
........
 
[root@mimy-centos7b src]# ./redis-cli -h 192.168.31.181 -p 9501
192.168.31.181:9501> info replication
# Replication
role:slave
master_host:192.168.31.168
master_port:9500
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:2317523
........
 
[root@localhost src]# ./redis-cli -h 192.168.31.129 -p 9502
192.168.31.129:9502> info replication
# Replication
role:slave
master_host:192.168.31.168
master_port:9500
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:2336225
........
 

五、數據同步、高可用方案驗證

1、數據同步

# 1、一開始三臺機都是同步的,沒有數據的;
192.168.31.168:9500> KEYS *
(empty list or set)
 
192.168.31.181:9501> keys *
(empty list or set)
 
192.168.31.129:9502> keys *
(empty list or set)
 
# 2、在主庫插入(KEY1,CHAOS MONKEY)
192.168.31.168:9500> SET KEY1 'CHAOS MONKEY'
OK
 
# 3、查詢另外兩個從庫是否同步了
192.168.31.181:9501> get KEY1
"CHAOS MONKEY"
 
192.168.31.129:9502> GET KEY1
"CHAOS MONKEY"
 
 
從129這臺機的日誌(/var/run/redis/redis.log)看,數據正在從168同步到129的從庫(截圖一)。另外,相同的同步的行爲也發生在從168到181的從庫(截圖二)。
 
另外,這裏要注意兩個從庫同步的時間是不一樣的,因爲我們之前設置了最大同時從主庫同步數據的從庫數(具體數據同步的行爲請看下圖日誌)。
sentinel parallel-syncs mymaster 1               # 若新主庫當選後,允許最大可以同時從新主庫同步數據的從庫數
 

2、高可用驗證

首先,我們通過命令“./redis-cli -h 192.168.31.168 -p 26379 info sentinel”隨便從一臺機看看sentinel的情況,目前主庫是192.168.31.168。
 
接着我們嘗試模擬主庫崩潰,先把168的主庫停掉,然後通過sentinel.log日誌發現主庫已經從168換成181。
  • 首先,181發現168下線,這是主觀失效;因爲我們在sentinel.conf中的設置了sentinel monitor mymaster 127.0.0.1 6379 2 , 這裏最後的2代表需要2個哨兵認爲主庫下線纔算是真正下線(即客觀失效)然後再進行選舉;
  • 接着,129或者168的哨兵也發現168下線,已經達到2臺,因此就把168主庫設成下線(客觀失效),開始選舉;
  • 接着,開始選舉,最終181被選舉成主庫。
 
 
登錄到181的redis上,通過INFO REPLICATION可以看到181也確實變成主庫,129變成181的從庫。
 
這個時候我們繼續嘗試一下新增KEY,從以下結果可以看出129是能夠正常從181(新主庫)同步數據。
192.168.31.181:9501> keys *
1) "KEY1"
2) "KEY2"
3) "KEY3"
 
192.168.31.129:9502> keys *
1) "KEY3"
2) "KEY2"
3) "KEY1"
 
192.168.31.181:9501> set KEY4 BUTTERFLY
OK
192.168.31.181:9501> keys *
1) "KEY1"
2) "KEY4"
3) "KEY2"
4) "KEY3"
 
192.168.31.129:9502> keys *
1) "KEY3"
2) "KEY2"
3) "KEY4"
4) "KEY1"

六、結語

當然一主兩從三哨兵的模式還是有一定的缺陷,例如如果是多主情況就不能主主複製等。但本來方案就是沒有完美的,有的只是量體裁衣。以後有時間再聊聊主從集羣模式。 
 
 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章