實踐 - 搭建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的投票仲裁機制是怎麼樣的?