基於Docker搭建Redis一主兩從三哨兵

這段時間正在學習Redis和容器相關的內容,所以想經過docker搭建一套redis主從系統來加深理解。看這篇文章可能你須要必定的docker基礎,以及對redis主從和哨兵機制有所瞭解。linux

此次實驗準備了三臺雲主機,系統爲Debian,ip分別爲:35.236.172.131 ,35.201.200.251,34.80.172.42。redis

首先分別在這三臺主機上安裝docker,而後每臺主機上啓動一個redis容器,運行redis-server服務,其中35.236.172.131做爲master,另外兩臺機器做爲slave,最後在三臺主機上再分別啓動一個redis容器,運行redis-sentinel。爲何仍是redis容器呢?由於sentinel實際上仍是一個redis-server,只不過是以sentinel模式執行,只能處理sentinel須要的一些命令。docker

安裝docker

docker的安裝有不少種方法,這裏就不介紹了。本次使用腳本安裝docker,Debian系統腳本安裝以下,其餘系統能夠參考Docker官網的安裝方法:docs.docker.com/install/lin…。不過下面的命令在官網命令的基礎上修改鏡像源爲阿里雲,由於國內鏡像每每會快一些。ubuntu

腳本安裝docker

在物理主機或者雲虛擬主機上運行下面的命令就能夠完成docker安裝了,固然我是在Debian系統上,其餘系統相應參考官網上的方法。bash

$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
複製代碼

啓動docker CE

docker是以客戶端和服務器模型運行的,所以須要先運行docker的服務器,服務器以daemon的形式運行。docker CE是docker的社區版本。服務器

$ sudo systemctl enable docker
$ sudo systemctl start docker
複製代碼

驗證docker是否安裝成功

下面的這條命令是從docker的官方倉庫拉取一個名爲hello-world的鏡像,並經過這個鏡像啓動一個容器。網絡

$ docker run hello-world
複製代碼

若是運行結果以下,出現了Hello from Docker!,說明docker安裝成功了app

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete 
Digest: sha256:6540fc08ee6e6b7b63468dc3317e3303aae178cb8a45ed3123180328bcc1d20f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
複製代碼

啓動容器搭建主從

docker安裝成功後,能夠開始部署redis服務了。先從docker官方公共倉庫拉取redis鏡像,而後修改redis服務的配置文件,最後啓動容器,啓動redis服務器。在多臺機器上運行redis服務器,並創建主從關係。curl

redis的主從是實現redis集羣和redis哨兵高可用的基礎,redis的主從結構使從能夠複製主上的數據,若是從與主之間網絡斷開,從會自動重連到主上。tcp

獲取Redis鏡像

下面的命令會拉取最新的官方版本的redis鏡像

$ docker pull redis
複製代碼

查看鏡像

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
redis               latest              bb0ab8a99fe6        7 days ago          95MB
hello-world         latest              fce289e99eb9        6 months ago        1.84kB
複製代碼

獲取並修改redis配置文件

redis官方提供了一個配置文件樣例,經過wget工具下載下來。我用的root用戶,就直接下載到/root目錄裏了。

$ wget http://download.redis.io/redis-stable/redis.conf
複製代碼

打開下載下來的文件後,能夠看到配置有不少。我只是搭建服務進行試驗因此只修改必要的幾項。若是要運用到線上,那必須全部的配置都按需求進行修改。

其中redis服務器的master和slave角色使用的配置文件還會有些不一樣,下面分別進行說明。

對於master而言,配置文件修改如下幾項

# 註釋這一行,表示Redis能夠接受任意ip的鏈接
# bind 127.0.0.1 

# 關閉保護模式
protected-mode no 

# 讓redis服務後臺運行
daemonize yes 

# 設定密碼(可選,若是這裏開啓了密碼要求,slave的配置裏就要加這個密碼. 只是練習配置,就不使用密碼認證了)
# requirepass masterpassword 

# 配置日誌路徑,爲了便於排查問題,指定redis的日誌文件目錄
logfile "/var/log/redis/redis.log"
複製代碼

對於slave而言,配置文件修改如下幾項:

# 註釋這一行,表示Redis能夠接受任意ip的鏈接
# bind 127.0.0.1 

# 關閉保護模式
protected-mode no 

# 讓redis服務後臺運行
daemonize yes 

# 設定密碼(可選,若是這裏開啓了密碼要求,slave的配置裏就要加這個密碼)
requirepass masterpassword 

# 設定主庫的密碼,用於認證,若是主庫開啓了requirepass選項這裏就必須填相應的密碼
masterauth <master-password>

# 設定master的IP和端口號,redis配置文件中的默認端口號是6379
# 低版本的redis這裏會是slaveof,意思是同樣的,由於slave是比較敏感的詞彙,因此在redis後面的版本中不在使用slave的概念,取而代之的是replica
# 將35.236.172.131作爲主,其他兩臺機器作從。ip和端口號按照機器和配置作相應修改。
replicaof 35.236.172.131 6379

# 配置日誌路徑,爲了便於排查問題,指定redis的日誌文件目錄
logfile "/var/log/redis/redis.log"
複製代碼

啓動容器

分別在主機和從機上按照上面的方法創建好配置文件,檢查無誤後就能夠開始啓動容器了。

咱們在三臺機器上分別將容器別名指定爲redis-1, redis-2, redis-3,這樣便於區分與說明,docker經過--name參數來指定容器的別名。redis-1是master上容器的別名,redis-2和redis-3是兩個slave上的別名。

下面以運行redis-3容器爲例說明容器的啓動過程。另外兩臺機器上的容器redis-1和redis-2操做是相同的,只是要注意master的配置文件和slave不一樣。不過首先要啓動主服務器,也就是redis-1容器。而後再啓動redis-2和redis-3。

# 首先之後臺模式運行容器
$ docker run -it --name redis-3 -v /root/redis.conf:/usr/local/etc/redis/redis.conf -d -p 6379:6379 redis /bin/bash
# 容器成功啓動後,會打印一個長串的容器ID
a3952342094dfd5a56838cb6becb5faa7a34f1dbafb7e8c506e9bd7bb1c2951b
# 經過ps命令查看容器的狀態,能夠看到redis-3已經啓動
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
a3952342094d        redis               "docker-entrypoint.s…"   8 minutes ago       Up 8 minutes        0.0.0.0:6379->6379/tcp   redis-3
複製代碼

上面已經啓動了容器,接下來進入容器裏啓動redis服務器。

# 以交互模式進入容器redis-3
$ docker exec -it redis-3 bash

# 建立日誌文件目錄
$ mkdir /var/log/redis/
$ touch /var/log/redis/redis.log

# 啓動redis服務器,若是沒有任何輸出,就說明成功了
$ redis-server /usr/local/etc/redis/redis.conf

# 在容器裏啓動一個redis客戶端
$ redis-cli 

# 執行info命令,查看服務器狀態
127.0.0.1:6379> info
...
# 若是是主,這裏的role的值會是master,若是是從,這裏的role的值會是slave
role:slave
# 對於slave,還要查看master_link_status這個屬性值。slave上這個屬性值爲up就說明主從複製是OK的,否者就有問題。若是從機狀態不爲up,首先排查主機的端口是否被限,而後查看redis日誌排查緣由
master_link_status:up
...

# 最後退出容器
$ exit
複製代碼

驗證主從複製

主從搭建成功後,能夠經過在master上寫入一個key-value值,查看是否會同步到slave上,來驗證主從同步是否能成功。

# 以交互模式進入容器redis-1中
$ docker exec -it redis-1 bash
複製代碼

運行一個redis-cli,向test_key寫入一個值

$ redis-cli
127.0.0.1:6379> set test_key hello-world
OK
複製代碼

在任意slave機器上進入容器,也運行一個redis-cli,查詢這個key的值。若是能查詢到這個值,且與主機上的值相同,說明主從同步成功。經測試,主動同步成功。

127.0.0.1:6379> get test_key 
"hello-world"
複製代碼

添加哨兵

主從結構搭建成功了,系統的可用性變高了,可是若是主發生故障,須要人工手動切換從機爲主機。這種切換工做不只浪費人力資源,更大的影響是主從切換期間這段時間redis是沒法對外提供服務的。所以,哨兵系統被開發出來了,哨兵能夠在主發生故障後,自動進行故障轉移,從從機裏選出一臺升級爲主機,並持續監聽着原來的主機,當原來的主機恢復後,會將其做爲新主的從機。

哨兵先監聽主,經過對主發送info命令,獲取到從的信息,而後也會監聽到從。另外哨兵都會像主訂閱__sentinel__:hello頻道,當有新的哨兵加入時,會向這個頻道發送一條信息,這條信息包含了該哨兵的IP和端口等信息,那麼其餘已經訂閱了該頻道的哨兵就會收到這條信息,就知道有一個新的哨兵加入。這些哨兵會與新加入和哨兵創建鏈接,選主是須要經過這個鏈接來進行投票。這個關係能夠用下面這個圖來描述

獲取並修改sentinel配置文件

經過wget命令獲取sentinel的配置文件

wget http://download.redis.io/redis-stable/sentinel.conf
複製代碼

修改配置文件如下幾項

# 讓sentinel服務後臺運行
daemonize yes 

# 修改日誌文件的路徑
logfile "/var/log/redis/sentinel.log"

# 修改監控的主redis服務器
# 最後一個2表示,兩臺機器斷定主被動下線後,就進行failover(故障轉移)
sentinel monitor mymaster 35.236.172.131 6379 2
複製代碼

啓動容器

與啓動redis容器相似,啓動一個別名爲sentinel的容器

$ docker run -it --name sentinel -p 26379:26379 -v /root/sentinel.conf:/usr/local/etc/redis/sentinel.conf -d redis /bin/bash
複製代碼

運行哨兵

# 進入容器
$ docker exec -it sentinel bash

# 建立日誌目錄和文件
$ mkdir /var/log/redis
$ touch /var/log/redis/sentinel.log

# 啓動哨兵
redis-sentinel /usr/local/etc/redis/sentinel.conf 

# 查看日誌,哨兵成功監聽到一主和兩從的機器
18:X 11 Jul 2019 13:25:55.416 # +monitor master mymaster 35.236.172.131 6379 quorum 2
18:X 11 Jul 2019 13:25:55.418 * +slave slave 35.201.200.251:6379 35.201.200.251 6379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 13:25:55.421 * +slave slave 34.80.172.42:6379 34.80.172.42 6379 @ mymaster 35.236.172.131 6379
複製代碼

在另外兩臺機器上按照一樣的方法在一個容器中運行sentinel,sentinel都使用相同的配置文件。

驗證failover(故障轉移)

爲了驗證哨兵機制下的自動主從切換,咱們將主上的redis進程kill掉。

稍等幾秒鐘後,就有另一臺從升級爲主機,實驗時是第三臺機器,也就是redis-3升級爲了主,用info命令查詢能夠看到redis-3服務器的角色變成的master。說明自動主從切換成功。

127.0.0.1:6379> info
...
# Replication
role:master
...
複製代碼

而後從新啓動以前被kill掉的master服務器,啓動後用info命令查看,能夠發現其變成了redis-3的從服務器。

下面這段日誌,描述了35.236.172.131做爲主啓動,執行故障轉移的master sentinel選舉,執行故障轉移,創建新的主從關係。

root@4355ca3260c5:/var/log/redis# cat sentinel.log 
17:X 11 Jul 2019 13:25:55.395 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
17:X 11 Jul 2019 13:25:55.395 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=17, just started
17:X 11 Jul 2019 13:25:55.395 # Configuration loaded
18:X 11 Jul 2019 13:25:55.398 * Running mode=sentinel, port=26379.
18:X 11 Jul 2019 13:25:55.398 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
18:X 11 Jul 2019 13:25:55.416 # Sentinel ID is 7d9a7877d4cffb6fec5877f605b975e00e7953c1
18:X 11 Jul 2019 13:25:55.416 # +monitor master mymaster 35.236.172.131 6379 quorum 2
18:X 11 Jul 2019 13:25:55.418 * +slave slave 35.201.200.251:6379 35.201.200.251 6379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 13:25:55.421 * +slave slave 34.80.172.42:6379 34.80.172.42 6379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 13:26:25.460 # +sdown slave 35.201.200.251:6379 35.201.200.251 6379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:04:23.390 * +sentinel sentinel 09aa7d2098ad2dc52e6e07d7bc6670f00f5ff3e3 172.17.0.3 26379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:04:25.418 * +sentinel-invalid-addr sentinel 09aa7d2098ad2dc52e6e07d7bc6670f00f5ff3e3 172.17.0.3 26379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:04:25.418 * +sentinel sentinel 7d9a7877d4cffb6fec5877f605b975e00e7953c1 172.17.0.3 26379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:04:25.456 * +sentinel-address-switch master mymaster 35.236.172.131 6379 ip 172.17.0.3 port 26379 for 09aa7d2098ad2dc52e6e07d7bc6670f00f5ff3e3
18:X 11 Jul 2019 14:08:34.338 * +sentinel-invalid-addr sentinel 09aa7d2098ad2dc52e6e07d7bc6670f00f5ff3e3 172.17.0.3 26379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:08:34.338 * +sentinel sentinel 28d3c0e636fa29ac9fb5c3cc2be00432c1b0ead9 172.17.0.3 26379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:08:36.236 * +sentinel-address-switch master mymaster 35.236.172.131 6379 ip 172.17.0.3 port 26379 for 09aa7d2098ad2dc52e6e07d7bc6670f00f5ff3e3
18:X 11 Jul 2019 14:11:12.151 # +sdown master mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:11:12.214 # +odown master mymaster 35.236.172.131 6379 #quorum 4/2
18:X 11 Jul 2019 14:11:12.214 # +new-epoch 1
18:X 11 Jul 2019 14:11:12.214 # +try-failover master mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:11:12.235 # +vote-for-leader 7d9a7877d4cffb6fec5877f605b975e00e7953c1 1
18:X 11 Jul 2019 14:11:12.235 # 7d9a7877d4cffb6fec5877f605b975e00e7953c1 voted for 7d9a7877d4cffb6fec5877f605b975e00e7953c1 1
18:X 11 Jul 2019 14:11:12.235 # 28d3c0e636fa29ac9fb5c3cc2be00432c1b0ead9 voted for 7d9a7877d4cffb6fec5877f605b975e00e7953c1 1
18:X 11 Jul 2019 14:11:12.235 # 09aa7d2098ad2dc52e6e07d7bc6670f00f5ff3e3 voted for 7d9a7877d4cffb6fec5877f605b975e00e7953c1 1
18:X 11 Jul 2019 14:11:12.294 # +elected-leader master mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:11:12.294 # +failover-state-select-slave master mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:11:12.394 # -failover-abort-no-good-slave master mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:11:12.453 # Next failover delay: I will not start a failover before Thu Jul 11 14:17:12 2019
18:X 11 Jul 2019 14:11:13.050 # +config-update-from sentinel 28d3c0e636fa29ac9fb5c3cc2be00432c1b0ead9 172.17.0.3 26379 @ mymaster 35.236.172.131 6379
18:X 11 Jul 2019 14:11:13.050 # +switch-master mymaster 35.236.172.131 6379 34.80.172.42 6379
18:X 11 Jul 2019 14:11:13.050 * +slave slave 35.201.200.251:6379 35.201.200.251 6379 @ mymaster 34.80.172.42 6379
18:X 11 Jul 2019 14:11:13.050 * +slave slave 35.236.172.131:6379 35.236.172.131 6379 @ mymaster 34.80.172.42 6379
18:X 11 Jul 2019 14:11:43.077 # +sdown slave 35.236.172.131:6379 35.236.172.131 6379 @ mymaster 34.80.172.42 6379
18:X 11 Jul 2019 14:11:43.077 # +sdown slave 35.201.200.251:6379 35.201.200.251 6379 @ mymaster 34.80.172.42 6379
18:X 12 Jul 2019 01:54:05.142 # -sdown slave 35.236.172.131:6379 35.236.172.131 6379 @ mymaster 34.80.172.42 6379
18:X 12 Jul 2019 01:54:15.087 * +convert-to-slave slave 35.236.172.131:6379 35.236.172.131 6379 @ mymaster 34.80.172.42 6379
複製代碼

總結

redis經過主從複製來實現高可用,可是發生故障時須要人工進行主從切換,效率低下。哨兵機制實現了redis主從的自動切換,提升了redis集羣的可用性,提升了redis集羣的故障轉移效率。

相關文章
相關標籤/搜索