上篇文章:
Redis原理之主從復制https://blog.csdn.net/sniper_fandc/article/details/149141103?fromshare=blogdetail&sharetype=blogdetail&sharerId=149141103&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link
目錄
1 哨兵機制恢復主節點故障流程
1.1 整體流程
1.2 sentinel節點作用
2 搭建主從結構+哨兵
2.1 docker拉取redis鏡像
2.2 編排redis數據節點
2.3 編排redis的哨兵節點(sentinel)
2.4 演示故障轉移
????????注意:從節點如何變為主節點?從節點主動執行slaveof no one命令,此時從節點變為主節點。但是如果是主節點掛了,從節點是不會自動變為主節點的。此時只有人工干預來選擇哪個從節點變為主節點,需要改變主從模式的拓撲結構,比較麻煩。而哨兵機制正式解決該問題的手段。
????????哨兵機制:Redis提供的高可用性的實現方案,它是獨立的redis-sentinel進程,不屬于redis提供的redis-server進程。
1 哨兵機制恢復主節點故障流程
1.1 整體流程
????????哨兵節點會和數據節點建立TCP長連接,并采用心跳包機制,定期向數據節點發送ping,數據節點需要回復pong。如果哨兵節點沒有收到pong響應,就會認為該節點不可達(發生故障)。如果是slave節點故障,對讀寫沒有太大影響;如果是master節點故障,則哨兵節點開始工作:
????????1.master節點故障,主從復制終止。
????????2.sentinel節點發現master故障(主觀下線),與其他sentinel進行“協商”,需要大多數sentinel都認為master故障(客觀下線),此時才會確認真正發生master故障(只有一個sentinel認為master故障不一定正確,因為可能是因為該sentinel節點發生網絡抖動,從而導致沒有收到pong,而實際可能master正常工作)。
????????3.sentinel節點之間通過Raft算法選舉一位作為領導(leader),leader負責故障轉移過程。
????????注意:Raft算法要求每個哨兵節點只有一票,率先發現故障的先發起自身成為leader的投票,其他哨兵節點先收到誰的投票就先投給誰,達到法定投票的節點成為leader。按照Raft算法規則,誰先發現故障,誰就更可能成為leader。因為偶數節點數有較大可能出現平票,因此最好選擇奇數節點個數的哨兵。
????????4.故障轉移:leader遠程控制某個slave執行slaveof no one命令,則該slave晉升為master節點,然后再控制其他slave進行slaveof到新的master節點,維護主從拓撲關系。當故障轉移后,leader會將新的master(ip和端口號)和拓撲關系通知其他客戶端。
????????注意:leader選擇slave的三個指標。先看優先級(配置文件的slave-priority或replica-priority),數值越小越優先;優先級一樣再看offset偏移量,數值越大越優先(說明數據量越接近原來的master);前兩個指標都一樣最后看run id,值越小越優先(由于run id是節點運行時redis自動隨機生成,因此這個指標實際上也是隨機選slave)。
1.2 sentinel節點作用
????????1.監控:監控所有的數據節點和其他哨兵節點。
????????2.故障轉移:master發生故障后負責從slave選擇新的master節點并維護主從拓撲結構。
????????3.通知:將故障轉移后的新master節點和拓撲關系通知給客戶端。
????????注意:sentinel節點數量通常設為奇數比較好,一般是3個。
2 搭建主從結構+哨兵
????????由于搭建真實的多物理機的redis節點成本較高,因此這里使用容器化技術來進行搭建。需要提前安裝docker和docker-compose,docker簡單來講是一個類似虛擬機的容器,它小巧輕量,提供了容器來統一配置環境信息,尤其是在多服務的環境中,配置很容易出現沖突,使用docker創建容器就可以實現多個服務的環境配置的沖突隔離。
????????docker-compose是容器編排工具,在docker中如果容器較多就容易出現多個容器之間的依賴關系(比如先后啟動順序),使用docker-compose就可以幫助我們進行管理。
2.1 docker拉取redis鏡像
????????使用命令來拉取redis的鏡像(拉取之間需要停掉所有的redis服務):
????????docker pull redis:5.0.9
2.2 編排redis數據節點
????????編排就是用yml文件來配置多個容器的信息,包括但不限于創建什么容器、容器參數信息(名稱、端口號等等),通過一個命令就能批量啟動這些容器。
????????這里搭建一主兩從的主從結構,需要定義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
????????其中,services下的master、slave1和slave2是服務的名字(自己起),image則是容器基于的鏡像,container_name是容器名稱,restart是如果節點掛了是否重啟,command則是啟動節點的方式,ports是端口映射(把物理機的端口映射到容器的端口,容器端口和物理機端口獨立,容器端口和容器端口獨立,映射了后就可以讓物理機訪問容器)。
????????使用命令docker-compose up -d(-d表示后臺方式啟動)即可啟動這三個容器:
????????這里可以使用redis-cli -p 6379來連接啟動的節點:
????????注意:為什么不把3個數據節點和3個哨兵節點放到一個yml文件?因為如果是哨兵節點先啟動,就會認為master節點故障,從而故障轉移,但是此時數據節點還未啟動,因此這樣操作無效。雖然不會對全局容器產生影響,但是對于執行日志的觀察不利。
2.3 編排redis的哨兵節點(sentinel)
????????這里操作和上述一樣:
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:26379networks:default:external:?truename: redis-data_default
????????由于sentinel啟動依賴配置文件sentinel.conf,而在運行過程中sentinel會對配置文件進行修改來適應具體節點的情況(配置重寫rewrite),因此不能使用同一個配置文件。volumes參數則描述了配置文件分別映射為三個文件,初始狀態一樣,但是一旦啟動文件內容就會發生變化。這三個配置文件(sentinel1.conf、sentinel2.conf和sentinel3.conf)內容如下:
bind 0.0.0.0port 26379sentinel monitor redis-master redis-master 6379 2sentinel down-after-milliseconds redis-master 1000
????????bing描述哨兵可被所有ip訪問,port描述哨兵的端口號,
????????sentinel monitor依次描述監控哪個主節點、主節點ip(這里使用主節點名稱類似域名,docker可自動解析為ip)、主節點端口號、法定選票(少數服從多數,達到選票數量才會一致認為master出現故障)。
????????sentinel down-after-milliseconds描述了心跳包超時時間,超過這個時間沒有接收到pong就認為master出現故障。
????????同時,由于使用docker-compose啟動一組容器,這相當于創建一個局域網(網絡名是docker-compose.yml所在的目錄+_default)。如果沒有networks字段的配置,這組sentinel節點就又創建了一個局域網,兩個局域網無法直接互相訪問。因此需要把這組節點加入到數據節點所在的局域網中,配置networks字段的原因正是上述闡述。
????????使用命令:docker network ls可以查看創建的局域網:
????????具體操作結果如下:
????????注意:上述操作中如果啟動容器失敗,就需要檢查配置文件,然后使用命令docker-compose down來關閉容器,再重新啟動。使用命令docker-compose logs可以查看docker容器的日志。上述和docker容器相關的命令必須在yml文件同級的目錄下進行。
????????使用命令docker ps -a查看目前啟動的容器:
2.4 演示故障轉移
????????使用docker stop redis-master命令關閉master節點:
????????觀察日志發現,sdown表示主觀下線,即sentinel-3哨兵節點首先發現master故障。odown表示客觀下線,sentinel-3獲得的票數達到法定票數(2票):
????????下圖表示投票記錄,其他兩個哨兵節點均給sentinel-3進行投票,因此sentinel-3成為leader:
????????sentinel-3作為leader選擇ip為172.18.0.4的slave節點(端口號為6380)為新的master,而172.18.0.2的節點是故障的master節點:
????????觀察6380的節點,role已經變成master,同時只有一個從節點連接,從節點的ip是182.18.0.3(端口號為6381):
????????如果使用docker start redis-master命令讓原來的master恢復,則它不會變為master,而是成為從節點:
????????由此可見,哨兵節點自動的完成了從監控=>發現故障=>選舉leader=>leader故障轉移=>轉移完成通知的過程,極大的保證了主從復制的高可用性。
下篇文章: