哨兵機制概念
在傳統主從復制機制中,會存在一些問題:
1. 主節點發生故障時,進行主備切換的過程是復雜的,需要人工參與,導致故障恢復時間無法保障。
2. 主節點可以將讀壓力分散出去,但寫壓力/存儲壓力是無法被分擔的,還是受到單機的限制。
哨兵機制就是為了解決第一個高可用問題的
當主節點出現故障時,哨兵機制能自動完成故障發現和故障轉移,并通知應用方,從而實現真正的高可用。?哨兵機制是一個分布式架構,其中包含若干個redis哨兵節點和Redis數據節點,每個哨兵節點會對數據節點和其余Sentinel節點進行監控,當它發現節點不可達時,會對節點做下線標識。如果下線的是主節點,它還會和其他的哨兵節點進行“協商”,當大多數哨兵節點對主節點不可達這個結論達成共識之后,它們會在內部“選舉”出一個領導節點來完成自動故障轉移的工作,同時將這個變化實時通知給Redis應用方。整個過程是完全自動的,不需要人工介入。
?
?
環境規劃
redis版本:5.0.9
我們將使用docker搭建redis哨兵環境
docker-compose?來進行容器編排
1)創建三個容器,作為redis的數據節點(主從結構,一主兩從)
2)創建三個容器,作為redis的哨兵節點
目錄結構:
搭建數據節點
docker-compose.yml是 Docker Compose 使用的配置文件,它定義了多個 Docker 容器的服務、網絡和卷的配置。通過這個文件,你可以使用一條命令來批量啟動多個docker容器
配置docker-compose.yml
version: '3.7'
services:master:image: 'redis:5.0.9'container_name: redis-masterrestart: alwayscommand: redis-server --appendonly yesports: - 6379:6379slave1:image: 'redis:5.0.9'container_name: redis-slave1restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6380:6379slave2:image: 'redis:5.0.9'container_name: redis-slave2restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6381:6379
version: '3.7'指定 Docker Compose 文件的版本。版本 3.7 支持更高級的功能和配置選項。
services:定義一組服務,每個服務對應一個容器。在這里,我們定義了三個服務,分別是主節點master和兩個從節點slave。
image:指定要使用的鏡像,這里是我們提前拉取的redis:5.0.9鏡像
container_name: 指定容器的名稱。這樣,你可以通過這個名稱來引用和管理容器。
restart: always:指定容器的重啟策略。在這里配置為always,表示無論容器是因何原因退出,Docker 都會自動重啟該容器。
command:設置啟動命令,為主節點和從節點配置不同的命令
ports:映射主機端口到容器端口。前一個是主機端口,后一個是容器端口。就是說,在主機里這三個redis分別是6379,6380,6381端口,映射到各自容器的6379端口
啟動docker compose配置的服務
在docker-compose.yml配置文件同級目錄下使用命令:
sudo docker-compose up -d
?up表示構建、(重新)創建、啟動并連接配置文件中定義的所有服務。如果某些服務已經在運行,up命令會重新啟動它們。
-d表示 --detach?選項,它會將服務在后臺運行。如果沒有-d選項,服務將會在前臺運行,并輸出日志信息到當前終端窗口
?
如果啟動后發現前面的配置有誤,需要重新操作,使用?docker-compose down 即可停止并刪除 剛才創建好的容器.?
?查看運行日志
同級目錄下使用命令:
sudo docker-compose logs
?
?可以看見成功加載了三個容器
也可以使用命令:
sudo docker ps -a
顯示容器的列表?
可以在最后一列看到名字分別是redis-slave1、redis-slave2、redis-master代表三個數據節點
搭建成功
驗證
連接主節點
可以看到,主節點,有兩個連接的從節點?
搭建哨兵節點
?(其實也可以把哨兵節點的yml配置文件和上面的配置文件寫到一起,這里分成兩組,主要是為了方便觀察)
哨兵節點配置
放在redis-sentinel目錄中,分別創建三個,內容完全相同
bind 0.0.0.0
port 26379
sentinel monitor redis-master redis-master 6379 2
sentinel down-after-milliseconds redis-master 1000
sentinel?monitor表示監聽的redis節點,第一個redis-master是給哨兵內部的名字,第二個是主節點ip,但是這里用的是docker,所以就寫容器名,會自動DNS成對應的ip,6379表示端口,2表示票數,如果有哨兵節點覺得主節點掛了,那就投1票,當票數大于等于2時,就認為主節點真的掛了,就會啟動后面的流程
sentinel down-after-milliseconds redis-master 1000主節點和哨兵之間通過心跳包來進行溝通.如果心跳包在指定的時間(1000ms)內還沒回來,就視為是節點出現故障.
為什么要創建三個一樣的文件,而不用同一個呢?
因為redis-sentinel 在運行中可能會對配置進行重寫,修改文件內容.如果用一份文件,就可能出現修改 混亂的情況.
配置docker-compose.yml
version: '3.7'
services:sentinel1:image: 'redis:5.0.9'container_name: redis-sentinel-1restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel1.conf:/etc/redis/sentinel.confports:- 26379:26379sentinel2:image: 'redis:5.0.9'container_name: redis-sentinel-2restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel2.conf:/etc/redis/sentinel.confports:- 26380:26379sentinel3:image: 'redis:5.0.9'container_name: redis-sentinel-3restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel3.conf:/etc/redis/sentinel.confports:- 26381:26379
networks:default:external:name: redis-data_default
volume:配置掛載的卷,將主機上的文件或目錄映射到容器內部。
networks:表示要加入的網絡而不是創建新的網絡,因為是兩個配置文件,會啟用兩個局域網,為了讓數據節點和哨兵節點互相認識并通信,所以要加入到一個網絡中。
啟動docker compose配置的服務
在docker-compose.yml配置文件同級目錄下使用命令:
sudo docker-compose up -d
?
查看運行日志
同級目錄下使用命令:
sudo docker-compose logs
?
可以發現正在監控主節點172.18.0.4 6379
驗證哨兵機制
主節點掛掉
sudo docker stop redis-master?
?查看哨兵日志
?這里從sdown master redis-master 172.18.0.4 6379之前都是啟動時的日志
后面是主節點掛了后的日志
sdown是主觀下線,就是說這個節點主觀認為主節點掛了(投一票)
odown是客觀下線,就是說主節點客觀掛了(票數超過設置)
表示票數達到3/2,超過規定,?認為主節點已經不能正常工作了,開啟選取新的主節點的流程
表示選取172.18.0.3作為主節點代替172.18.0.4?
重啟原來的主節點
sudo docker start redis-master
?
?這個節點變成從節點,并設置主節點為172.18.0.3
選取新主節點流程
主觀下線
當redis-master 宕機,此時redis-master和三個哨兵之間的心跳包就沒有了. 此時,站在三個哨兵的角度來看,redis-master出現嚴重故障。因此三個哨兵均會把redis-master判定為主觀下線(SDown)
并投一票故障
客觀下線
當故障得票數>=配置的法定票數之后,意味著redis-master故障這個事情被坐實了.此時觸發客觀下線(ODown)
選舉出哨兵的leader
因為選取新主節點的工作不能讓大家一起做,會亂套,所以現在需要在哨兵節點中選舉出一個領導leader節點,來選舉新主節點
這個選舉的過程涉及到 Raft 算法
1.每個哨兵節點都給其他所有哨兵節點,發起一個"拉票請求"
2.收到拉票請求的節點,會回復一個"投票響應".響應的結果有兩種可能,投or不投
如果已經發現主節點客觀下線,需要選舉leader,但是沒有收到拉票請求,就會投給自己,然后向其他哨兵拉票。
如果哨兵收到多個拉票請求,會投票給收到第一個請求的哨兵。
?3.一輪投票完成之后,發現得票超過半數的節點,自動成為leader
如果平票,再投一次
把哨兵節點的個數設置為奇數,可以減小平票的可能,提高效率
leader哨兵選舉新主節點
?leader 挑選出合適的slave成為新的 master
挑選規則:
1.比較優先級.優先級高(數值小的)的上位.優先級是redis配置文件中的配置項( slave-priority或replica-priority )
2.比較 replication offset 誰復制的數據多,高的上位
3.比較 run id ,誰的id小,誰上位.
選舉后
當某個slave節點被指定為master之后,
1. leader 指定該節點執行?slave no one ,成為master
2. leader 指定剩余的slave節點,都依附于這個新master
注意事項
? 哨兵節點不能只有一個,否則哨兵節點掛了也會影響系統可用性.
? 哨兵節點最好是奇數個,方便選舉leader,得票更容易超過半數.
? 哨兵節點不負責存儲數據,仍然是redis主從節點負責存儲.
? 哨兵+主從復制解決的問題是"提高可用性",不能解決"數據極端情況下寫丟失"的問題.
? 哨兵+主從復制不能提高數據的存儲容量,當我們需要存的數據接近或者超過機器的物理內存,這樣的結構就難以勝任了。
為了能存儲更多的數據,就引入了集群.