實踐 - 搭建Redis一主兩從三哨兵
原因:
最近在復習Redis的時候,學習到了為了提高Redis集群的高可用性,有一個模式為哨兵模式。哨兵模式的作用是為了在主節點出現阻塞或者錯誤,無法接收數據的時候,及時將從節點切換為主節點,由此保證Redis集群能夠保持正常狀態,保持高可用。
但是盡管引入哨兵模式能夠提高集群的高可用性,但是隨之帶來的有數據丟失,數據不一致問題。這些問題的原因有可能是因為主從異步復制的時候,主節點掛了,導致子節點接收數據不完整,出現數據不一致問題。也有可能是因為出現了腦裂問題,導致數據丟失問題等等。
但是知道概念后,就需要實踐一下才會知道這些問題出現的原因,避免紙上談兵。
部署節點:
那么一共需要的是六個節點,也就是要啟動六個Redis服務來模擬集群,那這里我使用Docker-Compose來實現集群。
1. 創建文件夾
一共是六個節點,分別是一個主機,兩個從機,三個哨兵。所以我們需要創建六個文件夾來對應這六個節點。
這是最終創建的結構樹。
.
|-- docker-compose.yml
|-- master
| |-- conf
| | `-- redis.conf
| `-- data
| |-- dump.rdb
| `-- nodes.conf
|-- sentinel1
| |-- conf
| | `-- sentinel.conf
| `-- data
|-- sentinel2
| |-- conf
| | `-- sentinel.conf
| `-- data
|-- sentinel3
| |-- conf
| | `-- sentinel.conf
| `-- data
|-- slave1
| |-- conf
| | `-- redis.conf
| `-- data
| `-- dump.rdb
`-- slave2
|-- conf
| `-- redis.conf
`-- data
`-- dump.rdb
從Redis官網獲取最新的Redis.conf,並復制到master,slave1,slave2的conf文件夾中。並獲取sentinel.conf復制到sentinel1,sentinel2,sentinel3的conf文件夾中。
2.編寫配置:
然后修改一下配置。
- 主機
bind 0.0.0.0 #設置所有地址訪問
protected-mode yes #這個是默認開啟的,也就是開啟安全模式
requirepass 123456 #設置密碼
以上的配置無論是主機還是從機都要配置,這是一樣的。
- 從機
replica-read-only yes #這個配置是從機只能讀,不能寫
replicaof 172.20.1.2 6379 #配置主機的ip和端口 在redis5.0以前則是salveof配置
masterauth 123456 #因為主節點設置了密碼,必須設置這個,否則會連不上主節點
這里說一下,在Vi下編輯文檔,查找,另起一行的命令如下。
/你要查找的詞 #按N往上找 按n往下找
o #直接在當前行下另起一行
- 哨兵
#這個配置的作用就是設置監聽的master節點的信息,mymaster可以換成符合規定的其他名字,后面的2是指當有兩個sentinel認為#這個master失效了,才會認為失效,從而進行主從切換
sentinel monitor mymaster 172.20.1.2 6379 2
#配置主從的的密碼,注意mymaster要對應剛才的配置項
sentinel auth-pass mymaster 123456
#這個配置項指定了需要多少失效時間,一個master才會被這個sentinel主觀地認為是不可用的。 單位是毫秒,默認為30秒
sentinel down-after-milliseconds mymaster 30000
#這個配置項指定了在發生failover主備切換時最多可以有多少個slave同時對新的master進行 同步,可以通過將這個值設為 1 來保證每次只有一個slave 處於不能處理命令請求的狀態。值越大,slave復制的越快,但同時也對主節點的網絡和硬盤負載造成壓力
sentinel parallel-syncs mymaster 1
#定義故障切換超時時間。默認180000,單位秒,即3min。
sentinel failover-timeout mymaster 180000
#設置運行期是不能改變notification-script和 client-reconfig-script ,避免一些安全問題
sentinel deny-scripts-reconfig yes
3.編寫docker-compose文件
然后就是編寫docker-compose文件了。
version: '3'
services:
master:
image: redis:latest
container_name: redis_master #master節點
volumes:
- ./master/conf/redis.conf:/etc/redis/redis.conf
- ./master/data:/data
networks:
redis_network:
ipv4_address: 172.20.1.2
command: /bin/bash -c "redis-server /etc/redis/redis.conf" #這句話就是要加載這個路徑下的配置
environment:
- TZ=Asia/Shanghai
- LANG=en_US.UTF-8
ports:
- "6379:6379"
slave1:
image: redis:latest
container_name: redis_slave_1 #slave1節點
volumes:
- ./slave1/conf/redis.conf:/etc/redis/redis.conf
- ./slave1/data:/data
networks:
redis_network:
ipv4_address: 172.20.1.3
command: /bin/bash -c "redis-server /etc/redis/redis.conf"
environment:
- TZ=Asia/Shanghai
- LANG=en_US.UTF-8
ports:
- "6380:6379"
slave2:
image: redis:latest
container_name: redis_slave_2 #slave2節點
volumes:
- ./slave2/conf/redis.conf:/etc/redis/redis.conf
- ./slave2/data:/data
networks:
redis_network:
ipv4_address: 172.20.1.4
command: /bin/bash -c "redis-server /etc/redis/redis.conf"
environment:
- TZ=Asia/Shanghai
- LANG=en_US.UTF-8
ports:
- "6381:6379"
sentinel1:
image: redis:latest
container_name: redis_sentinel_1 #sentinel1節點
ports:
- "26379:26379"
volumes:
- ./sentinel1/conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf
networks:
redis_network:
ipv4_address: 172.20.1.5
command: /bin/bash -c "redis-sentinel /usr/local/etc/redis/sentinel.conf"
sentinel2:
image: redis:latest
container_name: redis_sentinel_2 #sentinel2節點
ports:
- "26380:26379"
volumes:
- ./sentinel2/conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf
networks:
redis_network:
ipv4_address: 172.20.1.6
command: /bin/bash -c "redis-sentinel /usr/local/etc/redis/sentinel.conf"
sentinel3:
image: redis:latest
container_name: redis_sentinel_3 #sentinel3節點
ports:
- "26381:26379"
volumes:
- ./sentinel3/conf/sentinel.conf:/usr/local/etc/redis/sentinel.conf
networks:
redis_network:
ipv4_address: 172.20.1.7
command: /bin/bash -c "redis-sentinel /usr/local/etc/redis/sentinel.conf"
networks:
redis_network:
driver: bridge
ipam:
config:
- subnet: 172.20.1.0/24
執行docker-compose up -d創建容器。

一共出現六個容器,如果某個容器不見了,那就證明配置有誤。執行docker logs 容器id來查看日志。
新建三個終端來分別進入master,slave和sentinel節點。
4.驗證狀態
使用命令
docker exec -it redis_master bash
#進入后使用命令進入redis-cli,-a是指密碼,-h是指ip,-p是指端口
redis-cli -a 123456 -h 172.20.1.2 -p 6379
#使用命令查看從機信息
info replication
從節點有兩個,ip也給出了。
然后我們按照剛才的命令進入從機,試一下創建一個key,發現出現錯誤。這就是剛才從機配置的replica-read-only yes配置在發揮作用了。因為按照我們的設定,一主兩從,主節點是負責寫,從節點負責讀,讀寫分離,那么從節點當然無法寫入數據。
我們進入sentinel節點,注意:進入redis-cli的端口不是6379了,而是剛才配置的26379端口。執行info命令,往下划。
可以看到sentinel節點監控的master節點只有一個,而且ip也正是我們的master主機ip,slaves為2,sentinels為3,這說明我們的配置的一主兩從三哨兵是正常運行的。
測試:
我們嘗試在主節點寫入數據,看看是否會同步到從機中。
我們在從機查看是否有該key。
從機的確能獲取到主機所設置的key值,說明主從同步是正常的。
同時讀寫分離是Redis自帶的,通過配置slave,Redis會自動地讓從機進行讀操作,讓主機進行寫操作。這是Redis的主從模式所自帶的。
而在主從模式的基礎上添加哨兵模式,從而提高主從模式的高可用。
模擬故障
這里先模擬一個最常見的故障,就是master主機宕機,看看是否會進行主從切換。
這里直接stop掉master主機的容器。
然后過個30秒,在Sentinel的容器上執行命令
info Sentinel

然后發現master主機已經改變了,slave2從機節點被切換成為新的master節點。
總結:
通過以上步驟,我們完成了一主兩從三哨兵的搭建,同時也通過模擬一個最最常見的故障了測試哨兵模式的主從切換功能。那就來總結一下哨兵模式的功能吧。
- 故障轉移,能夠通過配置及時地將從機切換成主機。
- 故障發現,能夠通過Ping監控Master狀態。
- 配置中心,能夠統一配置所有節點的主節點信息。
優點:
- 哨兵模式是基於主從模式的,所有主從的優點,哨兵模式都具有。
- 主從可以自動切換,系統更健壯,可用性更高。
- Sentinel 會不斷的檢查 主服務器 和 從服務器 是否正常運行。當被監控的某個 Redis 服務器出現問題,Sentinel 通過API腳本向管理員或者其他的應用程序發送通知。
缺點:
- Redis較難支持在線擴容,對於集群,容量達到上限時在線擴容會變得很復雜。
主從模式解決了Redis的xx,哨兵模式解決了Redis的高可用性問題,但是面對在線擴容則顯得困難,所以才有了Cluster集群模式,通過水平拓展Redis節點,從而解決了擴容這個問題。后面我們會繼續研究Cluster集群的搭建與它的一些討論。
同時主從模式和哨兵模式中有一些功能值得我們去深究,例如Sentinel是如何通知其他從機切換主機的呢?Sentinel的投票仲裁機制是怎么樣的?
