Redis(三)部署Sentinel高可用集群

大家一定非常熟悉如何利用 Docker 启动单个 Redis 容器用于开发环境,本文将介绍如何利用 Docker Compose 模板在本机和云端部署基于 Sentinel 的高可用 Redis 3 集群。

Redis 集群可以在一组 redis 节点之间实现高可用性和 sharding。今天我们重点围绕 master-slave 的高可用模式来进行讨论,在集群中会有 1 个 master 和多个 slave 节点。当 master 节点失效时,应选举出一个 slave 节点作为新的 master。然而 Redis 本身(包括它的很多客户端)没有实现自动故障发现并进行主备切换的能力,需要外部的监控方案来实现自动故障恢复。
Redis Sentinel 是官方推荐的高可用性解决方案。它是 Redis 集群的监控管理工具,可以提供节点监控、通知、自动故障恢复和客户端配置发现服务。
今天我们的部署模型是 Redis Sentinel 介绍的实例二,也是实战中比较常见的一种部署模式:
image.png
本文所有示例代码都可以从 https://github.com/AliyunContainerService/redis-cluster 获得
本文采用的 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 集群了

  • 在这里 master 和 2 个 slave 部署到不同的宿主机节点中
  • 3 个 sentinel 部署到不同的宿主机节点中

这样任何一个宿主机节点失效,都不会导致 Redis 集群失败

总结

文章介绍了如何在本地部署一个 Redis 集群,并利用 Redis Sentinel 实现自动化的主从切换。并在此基础上利用阿里云容器服务扩展,一键部署一个真正的高可用分布式 Redis 集群。
对于 Redis 而言,阿里云提供了云数据库 Redis 版,对于大部分对 SLA 有要求的客户我们建议在生产环境使用 Redis 云服务。但是如果大家对版本、配置有特殊要求的时候,使用 Docker 部署 Redis 也是非常方便的。
出于性能考虑,在 Docker 容器中运行 Redis 不建议采用 bridge 网络对外提供访问,如需对外部 VM 或应用提供服务建议采用 host 网络模式,并注意安全保护;如果只是对集群中容器提供 redis 访问,则容器服务默认提供的跨宿主机容器网络会提供优化而安全的网络配置。同时建议在 Docker 容器设置中,给 Redis 容器配置合适的内存设置。
本文也给大家提供了一个示例,如何采用 Docker 的方式开发分布式应用并在云端部署生产级别环境。阿里云容器服务不但支持 docker-compose 模板提供的容器功能,使得本地开发的 Docker 镜像和编排模板可以轻松上云;更提供了灵活的部署约束描述,使得对分布式应用的部署和控制变得非常方便。

https://alicharles.oss-cn-hangzhou.aliyuncs.com/static/images/mp_qrcode.jpg
文章目录
  1. 单机部署 Redis 集群
  2. 云端部署高可用 Redis 集群
  3. 总结