1. 程式人生 > >使用Docker Compose部署基於Sentinel的高可用Redis叢集

使用Docker Compose部署基於Sentinel的高可用Redis叢集

14692678677279

大家一定非常熟悉如何利用Docker啟動單個Redis容器用於開發環境,本文將介紹如何利用Docker Compose模板在本機和雲端部署基於Sentinel的高可用Redis 3叢集。

Redis叢集可以在一組redis節點之間實現高可用性和sharding。今天我們重點圍繞master-slave的高可用模式來進行討論,在叢集中會有1個master和多個slave節點。當master節點失效時,應選舉出一個slave節點作為新的master。然而Redis本身(包括它的很多客戶端)沒有實現自動故障發現並進行主備切換的能力,需要外部的監控方案來實現自動故障恢復。

Redis Sentinel是官方推薦的高可用性解決方案。它是Redis叢集的監控管理工具,可以提供節點監控、通知、自動故障恢復和客戶端配置發現服務。

今天我們的部署模型是 Redis Sentinel 介紹的例項二,也是實戰中比較常見的一種部署模式:

14692659415657

本文采用的Redis映象全部基於Docker提供的Redis官方映象3.2.1

單機部署Redis叢集

下面的測試需要本地環境已經安裝Docker Engine和Docker Compose,推薦使用Docker for Mac/Windows。想在雲端部署的同學可以直接跳到下一節

下載程式碼

git clone https://github.com/AliyunContainerService/redis-cluster
cd redis-cluster

目錄下面的docker-compose.yml模板定義Redis叢集的服務組成

master:
  image: redis:3
slave:
  image: redis:3
  command: redis-server --slaveof redis-master 6379
  links:
    - master:redis-master
sentinel:
  build: sentinel
  environment:
    - SENTINEL_DOWN_AFTER=5000
    - SENTINEL_FAILOVER=5000    
  links:
    - master:redis-master
    - slave

在模板中定義了下面一系列服務

  • master: Redis master
  • slave: Redis slave
  • sentinel: Redis Sentinel

其中sentinel服務的Docker映象是由 "./sentinel" 目錄中的Dockerfile構建完成,只是在官方Redis映象上添加了sentinel.conf配置檔案,並以sentinel模式啟動容器。其配置檔案如下,其中包含了sentinel對名為"mymaster"的叢集的監控配置:

sentinel monitor mymaster redis-master 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 5000

細節請參見sentinel.conf配置自身。

注意:

  • slave和sentinel容器初始化配置的Redis master節點主機名為"redis-master",這裡我們利用了Docker容器連線的別名機制來連線master和sentinel/slave容器例項
  • 由於我們會部署3個Sentinel,我們把sentinel的"quorum"設定為2,只有兩個sentinel同意故障切換,才會真正切換相應的redis master節點。

下面我們先構建 sentinel 服務所需 Docker image

docker-compose build

一鍵部署並啟動Redis叢集

docker-compose up -d

這時我們可以檢查叢集狀態,應該是包含3個容器,1個master, 1個slave,和1個sentinel

docker-compose ps

顯示結果如下

         Name                        Command               State          Ports        
--------------------------------------------------------------------------------------
rediscluster_master_1     docker-entrypoint.sh redis ...   Up      6379/tcp            
rediscluster_sentinel_1   docker-entrypoint.sh redis ...   Up      26379/tcp, 6379/tcp 
rediscluster_slave_1      docker-entrypoint.sh redis ...   Up      6379/tcp     

我們可以伸縮sentinel的例項數量到3個

docker-compose scale sentinel=3

伸縮slave的例項數量到2個,這樣我們就有3個redis例項了(包含一個master)

docker-compose scale slave=2

檢查叢集狀態,結果如下

docker-compose ps

         Name                        Command               State          Ports        
--------------------------------------------------------------------------------------
rediscluster_master_1     docker-entrypoint.sh redis ...   Up      6379/tcp            
rediscluster_sentinel_1   docker-entrypoint.sh redis ...   Up      26379/tcp, 6379/tcp 
rediscluster_sentinel_2   docker-entrypoint.sh redis ...   Up      26379/tcp, 6379/tcp 
rediscluster_sentinel_3   docker-entrypoint.sh redis ...   Up      26379/tcp, 6379/tcp 
rediscluster_slave_1      docker-entrypoint.sh redis ...   Up      6379/tcp            
rediscluster_slave_2      docker-entrypoint.sh redis ...   Up      6379/tcp            

我們可以利用下面的測試指令碼來模擬master節點失效,並驗證Redis叢集的自動主從切換。

./test.sh

這個測試指令碼實際上利用 docker pause 命令將 Redis master容器暫停,sentinel會發現這個故障並將master切換到其他一個備用的slave上面。

執行結果如下

Redis master: 172.17.0.2
Redis Slave: 172.17.0.3
------------------------------------------------
Initial status of sentinel
------------------------------------------------
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.17.0.2:6379,slaves=2,sentinels=3
Current master is
172.17.0.2
6379
------------------------------------------------
Stop redis master
rediscluster_master_1
Wait for 10 seconds
Current infomation of sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.17.0.3:6379,slaves=2,sentinels=3
Current master is
172.17.0.3
6379
------------------------------------------------
Restart Redis master
rediscluster_master_1
Current infomation of sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.17.0.3:6379,slaves=2,sentinels=3
Current master is
172.17.0.3
6379

我們可以利用Docker Compose方便地在本地驗證Redis叢集的部署和故障恢復,但是這還不是一個分散式的高可用部署。我們下面會利用阿里雲容器服務來進行驗證

雲端部署高可用Redis叢集

阿里雲容器服務 在相容Docker Compose編排模板的基礎上,做了大量的擴充套件。能夠更好地幫助我們在Docker叢集中部署分散式應用。

首先您需要建立一個包含至少三個節點的叢集(否則您需要註釋掉相應的"affinity:service"部署約束)

然後我們利用下面的 docker compose模板部署高可用Redis叢集

master:
  image: redis:3
  environment:
    - affinity:service!=slave
  restart: always
slave:
  image: redis:3
  command: redis-server --slaveof redis-master 6379
  environment:
    - affinity:service!=master
    - affinity:service!=slave
  labels: 
    aliyun.scale: "2"
  restart: always
  links:
    - master:redis-master
sentinel:
  image: registry.aliyuncs.com/acs-sample/redis-sentinel:3
  environment:
    - affinity:service!=sentinel
  labels: 
    aliyun.scale: "3"
  restart: always
  links:
    - master:redis-master
    - slave

這裡使用了預編譯的sentinel映象"registry.aliyuncs.com/acs-sample/redis-sentinel:3"

更重要是,引入了一些阿里雲擴充套件使得對分散式應用更好地控制容器在宿主機節點的部署

  • aliyun.scale 標籤:描述了服務的例項數量
  • affinity:service 環境變數描述了服務的部署約束:比如對於Redis slave而言,我們不希望在一個宿主機節點上同時部署master和slave,或多個slave,我們可以方便用示例中的方法描述這些約束。

關於這些的詳盡解釋請參見幫助文件

一鍵部署之後,我們就已經有一個真正高可用的Redis叢集了

  1. 在這裡master和2個slave部署到不同的宿主機節點中
  2. 3個sentinel部署到不同的宿主機節點中
    這樣任何一個宿主機節點失效,都不會導致Redis叢集失敗

14692757591755

總結

文章介紹瞭如何在本地部署一個Redis叢集,並利用Redis Sentinel實現自動化的主從切換。並在此基礎上利用阿里雲容器服務擴充套件,一鍵部署一個真正的高可用分散式Redis叢集。

對於Redis而言,阿里雲提供了雲資料庫 Redis 版,對於大部分對SLA有要求的客戶我們建議在生產環境使用Redis雲服務。但是如果大家對版本、配置有特殊要求的時候,使用Docker部署Redis也是非常方便的。

出於效能考慮,在Docker容器中執行Redis不建議採用bridge網路對外提供訪問,如需對外部VM或應用提供服務建議採用host網路模式,並注意安全保護;如果只是對叢集中容器提供redis訪問,則容器服務預設提供的跨宿主機容器網路會提供優化而安全的網路配置。同時建議在Docker容器設定中,給Redis容器配置合適的記憶體設定。