文章目錄
- 為什么要有哨兵模式呢?
- 哨兵自動恢復故障主節點
- 使用docker搭建分布式系統
- 查看哨兵節點工作
- 哨兵選舉新的主節點的流程
- 總結
為什么要有哨兵模式呢?
主從復制的問題
Redis 的主從復制模式可以將主節點的數據改變同步給從節點,這樣從節點就可以起到兩個作?:
第?,作為主節點的?個備份,?旦主節點出了故障不可達的情況,從節點可以作為后備 “頂” 上
來,并且保證數據盡量不丟失(主從復制表現為最終?致性)。第?,從節點可以分擔主節點上的讀
壓?,讓主節點只承擔寫請求的處理,將所有的讀請求負載均衡到各個從節點上。
但是主從復制模式并不是萬能的,它同樣遺留下以下?個問題:
- 主節點發?故障時,進?主備切換的過程是復雜的,需要完全的??參與,導致故障恢復時間?法保障。
- 主節點可以將讀壓?分散出去,但寫壓?/存儲壓?是?法被分擔的,還是受到單機的限制。
其中第?個問題是?可?問題,即 Redis 哨兵主要解決的問題。第?個問題是屬于存儲分布式的問題,后面Redis集群就是解決這個問題的。目前先解決第一個問題。
所以當主節點由于死機等問題,無法為客戶端提供服務時,就需要通知大量的客戶端,要更換主節點了。這對于已經部署好一定規模的客戶端集群來說,是無法接受的,且更換主節點需要人工干預,耗時長,對效率大打折扣,所以,就引入了哨兵(Redis Sentinel)來解決這個問題。
哨兵機制是一個獨立的redis-sentinel進程,不用來存儲數據,而是用來監控redis的數據節點。
人工干預情況下:
依然有許多問題,如果引入了哨兵機制自動修復節點,會大大提高效率。
哨兵自動恢復故障主節點
單獨的哨兵(redis sentinel)進程,提供了多個,這里以三個為例。(哨兵節點,最好是搞奇數個,最少是3個,一般情況下,都是搞三個。)
提供多個哨兵來監控主從節點的原因是防止單獨的哨兵出現誤判某個主節點掛了的情況。
還有如果單獨一個哨兵節點,如果它自己本身都掛了,那就無法自動恢復故障的主節點了。
這些哨兵會對所有要監控的主從節點進行TCP的長連接,連接成功后,定期向節點發送心跳檢測(這里的心跳檢測是應用層實現的,不是tcp中的keep-alive,應用層實現的心跳檢測一般是簡單的ping,pong)
如果發現某一個主節點不回復心跳檢測了,說明有可能掛了,此時多個哨兵討論一致后,如果認為該主節點真的掛了,則會挑選出一個哨兵節點,由這個哨兵節點按照某些挑選規則,挑選出一個新的主節點。
挑選出新的主節點后,哨兵節點會自動控制該被選中的節點,執行slaveof no one,讓他直接稱為新的主節點,并控制其他從節點,修改slaveof到新的主節點上。
哨兵節點會自動通知所有客戶端,告訴他們新的主節點是誰,后續客戶端再進行寫操作,就會針對新的主節點進行操作了。
使用docker搭建分布式系統
按理說,上面的6個節點是要部署在6臺不同的服務器主機上的。
一方面為了高可用,不至于一臺主機掛了,影響到其他主機。
一方面就是為了多使用其他主機的硬件資源,來提高效率。
虛擬機可以解決,但是非常吃硬件性能,一般的電腦是搞不起的。
所以使用docker,就能解決上述問題。
docker是一個輕量級虛擬機,既能起到像虛擬機一樣的隔離環境作用,又不會吃太多硬件資源。
docker關鍵字:”容器“,容器就是一個輕量級的虛擬機。
操作步驟:
- 1.安裝docker和docker-compose
ubuntu下:apt install docker, apt install docker-compose - 2.停止之前的redis服務器
service redis-server stop ,或者ps axu | grep redis,查看redis服務器進程的pid,kill -9 pid 即可。 - 3.使用docker獲取到redis的鏡像
簡單解釋一下docker的鏡像和容器的關系。
鏡像相當于可執行程序,容器相當于進程。
要啟動一個進程,那就要啟動一個可執行程序,才能成功啟動進程。
換句話說,要創建一個容器,那就得有描述該容器的一個模板,根據模板刻畫一個容器出來,才能使用。所以獲取redis鏡像,就相當于獲取相關的容器的可執行程序。
鏡像可以自己構建,也可以拿別人構建好的(官方給的docker hub,類似github,有大量開源的鏡像)
拉取鏡像命令
docker pull redis(docker pull默認就是從配置好的docker hub中拉取的)
檢查是否安裝成功:
docker images
如果看到有redis的鏡像,則說明安裝成功了。
接下來則使用一些配置文件(yml)格式,來實現使用簡單的命令控制多個redis節點,這些節點在docker就是一個個容器,一個節點就使用一個容器。
簡單理解yml格式:
yml格式相對于xml格式來說,xml格式一般都是以標簽的形式成對出現的。
<student><id>1</id><name>張三</name>
</student>
這種格式比較啰嗦,且空間大。
后來就有了json:
{id: 1,name: ”張三“
}
json格式寫起來方便,還減少了空間,json以{}表示層級結構的。
而對于yml格式來說,與json格式有些相似之處:
student:id: 1,name: 張三
yml是以縮進格式來表示層級結構的。
下面創建6個容器,三個是作為redis的數據節點(一主兩從)
三個是作為哨兵節點。
先創建一個目錄
mkdir -p redis/
cd redis/
mkdir -p redis-data/
mkdir -p redis-setinel/
這兩個目錄一個是放redis的數據節點,一個是放哨兵節點的。
cd redis-data/
vim docker-compose.yml (注意:配置文件的名字是固定的,不要改)
(注意縮進表示層級)
version: '3.7' # 版本號
services: # services中的master,slave1是自己設定的名字master:image: 'redis' # 要使用的鏡像名container_name: redis-master # 容器名字restart: always # 一些配置command: redis-server --appendonly yes ports: #這里重點說明- 6379:6379slave1:image: 'redis'container_name: redis-slave1restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379#這里可以直接通過容器名字,直接被docker進行類似域名解析的操作,獲取到redis服務器的ip了ports:- 6380:6379slave2:image: 'redis'container_name: redis-slave2restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6381:6379
port重點說明,docker 中的容器就是一個輕量級的虛擬機,可以隔離環境。
容器內的端口號和容器外的端口好可以相同的。
比如容器內可以使用6379,容器外也可以使用6379。
彼此不沖突。
但是如果想在容器外能夠訪問到容器里面的端口號,
就可以把容器內部的端口號映射成宿主機的端口號。
ports:
- 6380:6379
第一個port是宿主機的端口號,第二個port是容器內的端口號
相當于容器外(宿主機)映射后的端口號就是第一個,第二個就是容器內部自己的端口號
后續想要訪問容器內的某個端口號,就可以直接通過訪問宿主機這個映射的端口號,就等于訪問容器內的那個端口號了。
但是也要注意,映射出去的端口號也不要再使用,防止沖突。
啟動剛才配置的所有容器
docker-compose up -d
通過docker-compose logs就能看到日志信息。
netstat -anp | grep 端口號,通過grep剛才在配置文件寫好的端口號:6379,6380,6381,就能看到三個redis節點已經起來了。
下面要創建三個redis哨兵節點的容器。
cd /redis/redis-sentinel/
vim 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
解釋networks:指定當前所處的網絡是redis-
data_default。
接下來創建三個redis哨兵節點的配置文件。
sentinel1.conf,sentinel2.conf,sentinel3.conf。
都放在redis-sentinel/目錄下。
.conf配置文件信息如下
bind 0.0.0.0
port 26379
sentinel monitor redis-master redis-master 6379 2
sentinel down-after-milliseconds redis-master 1000
docker-compose up -d
創建三個哨兵節點
docker network ls
就能看到,只有一個局域網redis-data,而不是有redis-data又有redis-sentinel,這是因為.yml文件的network的作用。
查看哨兵節點工作
接下來就可以查看哨兵節點如何工作了。
docker ps -a,查看工作中的容器,就有三個redis的哨兵節點,三個redis主從節點。
接下來手動掛掉主節點
docker stop + 主節點名字(這里是redis-server)
此時主節點掛了,此時哨兵節點已經開始工作了
docker-compose logs ,查看日志
可以看到哨兵已經選出了新的主節點了。所以故障恢復完成。
哨兵選舉新的主節點的流程
細節都在圖中了,看圖