基于Sentinel的高可用Redis集群

首先声明一下,本文根据官网修改配置,所以有些并不适用,本人最后采用的是最后一种方法。

概述

Redis-Sentinel哨兵机制为Redis提供了高可用性,这意味着你可以使用哨兵模式创建一个可以不用人为干预而能够自动地应对各种故障的Redis部署。与此同时,Redis-Sentinel哨兵机制还为Redis提供了如下功能:

监控:哨兵不断地检查master和slave是否正常运行。

通知:当被监控的某台Redis实例出现故障时,哨兵可以通过API通知系统管理员和其他的应用程序。

自动故障转移:如果一个master不正常运行了,哨兵可以启动一个故障转移进程,将一个slave升级成为master,其他的 slave被重新配置使用新的master,并且应用程序使用Redis服务端通知的新地址。

配置提供者:哨兵作为Redis客户端发现的权威来源:客户端连接到哨兵请求当前可靠的master的地址。如果发生故障,哨兵将报告新地址。

哨兵的分布式特性

Redis哨兵是一个分布式系统,哨兵自身被设计成和多个哨兵进程一起合作运行,有多个哨兵进程合作的好处有:

a. 当多个哨兵对一个master不再可用达成一致时才会执行故障转移,这会降低错误判断的概率。

b. 即使在不是所有的哨兵都工作时哨兵也会工作,使系统健壮的抵抗故障,毕竟在故障系统里单点故障没有什么意义。

安装Redis-Sentinel集群

 

redis.conf配置

Master主节点(172.16.250.234)的 redis.conf 配置如下:

 

#后台启动

daemonize yes
pidfile "/var/run/redis_6379.pid"
port 6379
timeout 0
tcp-keepalive 300
loglevel notice
logfile "/usr/local/redis-4.0.10/logs/redis.log"
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename "dump.rdb"
dir "/usr/local/redis-4.0.10/rdbs"
#如果做故障切换,不论主从节点都要填写密码且要保持一致
masterauth "123456"
slave-serve-stale-data yes
slave-read-only yes
repl-disable-tcp-nodelay no
slave-priority 99
#当前redis密码
requirepass "123456"
appendonly yes
appendfilename "appendonly.aof"
#appendfsync always
#appendfsync everysec
appendfsync no
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value -2
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes

Slave从节点(172.16.250.239,172.16.250.240)与Master主节点(172.16.250.234)的 redis.conf 配置内容基本相同,只是额外增加了一行主节点的配置信息。

#配置主节点信息(只在从节点中添加)
slaveof 172.16.250.234 6379
sentinel.conf配置
Master主节点(172.16.250.234)和Slave从节点(172.16.250.239,172.16.250.240)的 sentinel.conf 配置相同,内容如下:
# 哨兵sentinel实例运行的端口 默认26379
daemonize yes
port 26379
protected-mode no
# 哨兵sentinel的工作目录
dir "/usr/local/redis-4.0.10/sentinel-tmp"
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
# master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成
# quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时客观上认为主节点失联了
sentinel monitor redis-master 172.16.250.234 6379 2
# sentinel auth-pass <master-name> <password>
# 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码
# 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码
sentinel auth-pass redis-master 123456
# sentinel down-after-milliseconds <master-name> <milliseconds>
# 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时哨兵主观上认为主节点下线 默认30秒
sentinel down-after-milliseconds redis-master 30000
# sentinel failover-timeout <master-name> <milliseconds>
# 故障转移的超时时间 failover-timeout 可以用在以下这些方面:
# 1. 同一个sentinel对同一个master两次failover之间的间隔时间。
# 2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
# 3.当想要取消一个正在进行的failover所需要的时间。
# 4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
# 默认三分钟
sentinel failover-timeout redis-master 180000
# sentinel parallel-syncs <master-name> <numslaves>
# 指定在发生failover主备切换时最多可以有多少个slave同时对新的master进行同步,
# 这个数字越小,完成failover所需的时间就越长,
# 但是如果这个数字越大,就意味着越多的slave因为replication而不可用。
# 可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
sentinel parallel-syncs redis-master 1
# 配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常发邮件通知相关人员。
# 对于脚本的运行结果有以下规则:
# 若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
# 若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
# 如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。# 一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
#
# 通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,
# 这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,
# 一个是事件的类型,
# 一个是事件的描述。
# 如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
# #通知脚本
# sentinel notification-script <master-name> <script-path>
# sentinel notification-script redis-master /var/redis/notify.sh
#
# 客户端重新配置主节点参数脚本
# 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于maser地址已经发生改变的信息。
# 以下参数将会在调用脚本时传给脚本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>总是“failover”,
# <role>是“leader”或者“observer”中的一个。
# 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的
# 这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentinel client-reconfig-script <master-name> <script-path>
# sentinel client-reconfig-script redis-master /var/redis/reconfig.sh

配置完成之后,先创建好相应目录,并使用如下命令分别启动Redis和Sentinel集群:

 

[root@master src]# mkdir ../logs

[root@master src]# mkdir ../rdbs

[root@master src]# mkdir ../sentinel-tmp

[root@master src]# ./redis-server ../redis.conf

[root@master src]# ./redis-sentinel ../sentinel.conf

 停止服务使用如下命令:

 

[root@master src]# pkill ./redis-server

[root@master src]# pkill ./redis-sentinel

 集群启动成功之后,登录 Redis 客户端查看节点的复制信息。

 

上面这个没有必要用吧,集群没有那么多,反正我是没有那么多钱的。

下面就是用docker去配置

使用Docker Compose部署基于Sentinel的高可用Redis集群

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

Redis集群可以在一组redis节点之间实现高可用性和sharding。今天我们重点围绕master-slave的高可用模式来进行讨论,在集群中会有1个master和多个slave节点。当master节点失效时,应选举出一个slave节点作为新的master。然而Redis本身(包括它的很多客户端)没有实现自动故障发现并进行主备切换的能力,需要外部的监控方案来实现自动故障恢复。

Redis Sentinel是官方推荐的高可用性解决方案。它是Redis集群的监控管理工具,可以提供节点监控、通知、自动故障恢复和客户端配置发现服务。

我们的部署模型是 Redis Sentinel 介绍的实例二,也是实战中比较常见的一种部署模式:

单机部署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集群失败

总结

文章介绍了如何在本地部署一个Redis集群,并利用Redis Sentinel实现自动化的主从切换。并在此基础上利用阿里云容器服务扩展,一键部署一个真正的高可用分布式Redis集群。

对于Redis而言,阿里云提供了云数据库 Redis 版,对于大部分对SLA有要求的客户我们建议在生产环境使用Redis云服务。但是如果大家对版本、配置有特殊要求的时候,使用Docker部署Redis也是非常方便的。

出于性能考虑,在Docker容器中运行Redis不建议采用bridge网络对外提供访问,如需对外部VM或应用提供服务建议采用host网络模式,并注意安全保护;如果只是对集群中容器提供redis访问,则容器服务默认提供的跨宿主机容器网络会提供优化而安全的网络配置。同时建议在Docker容器设置中,给Redis容器配置合适的内存设置。

 

 但但是这是在阿里云的特殊搭建方法,下面看看在华为云和阿里云通俗一点的搭建方法。

 1. 创建Redis主从资源编排文件

 

version: '2'
services:
  master:
    image: redis       ## 镜像
    container_name: redis-master
    command: redis-server --requirepass 123456
    ports:
    - "6379:6379"
    networks:
    - sentinel-master
  slave1:
    image: redis                ## 镜像
    container_name: redis-slave-1
    ports:
    - "6380:6379"           ## 暴露端口
    command: redis-server --slaveof redis-master 6379 --requirepass 123456 --masterauth 123456 
    depends_on:
    - master
    networks:
    - sentinel-master
  slave2:
    image: redis                ## 镜像
    container_name: redis-slave-2
    ports:
    - "6381:6379"           ## 暴露端口
    command: redis-server --slaveof redis-master 6379 --requirepass 123456 --masterauth 123456
    depends_on:
    - master
    networks:
    - sentinel-master
networks:
  sentinel-master:

2. 创建配置哨兵文件

由于使用docker环境,所以ip为docker内的内部ip,可使用如下命令获取master节点的ip地址。

docker inspect 容器id

可获取到容器在同一网络环境下的内网ip

哨兵配置文件sentinel.conf如下:

port 26379
dir /tmp
sentinel monitor mymaster 172.28.0.3 6379 2
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000 
sentinel deny-scripts-reconfig yes

第三行表示Redis监控一个叫做mymaster的运行在172.28.0.3:6379的master,投票达到2则表示master以及挂掉了。

第四行设置主节点的密码 

第五行表示在一段时间范围内sentinel向master发送的心跳PING没有回复则认为master不可用了。

第六行的parallel-syncs表示设置在故障转移之后,同时可以重新配置使用新master的slave的数量。数字越低,更多的时间将会用故障转移完成,但是如果slaves配置为服务旧数据,你可能不希望所有的slave同时重新同步master。因为主从复制对于slave是非阻塞的,当停止从master加载批量数据时有一个片刻延迟。通过设置选项为1,确信每次只有一个slave是不可到达的。

第七行表示10秒内mymaster还没活过来,则认为master宕机了。

复制粘贴出相同的三份

cp sentinel.conf sentinel1.conf

cp sentinel.conf sentinel2.conf

cp sentinel.conf sentinel3.conf

3. 创建哨兵集群资源编排文件

置哨兵的网络环境和主从容器的环境相同。

version: '2'
services:
  sentinel1:
    image: redis       ## 镜像
    container_name: redis-sentinel-1
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    volumes:
    - "./sentinel.conf:/usr/local/etc/redis/sentinel.conf"
  sentinel2:
    image: redis                ## 镜像
    container_name: redis-sentinel-2
    ports:
    - "26380:26379"           
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    volumes:
    - "./sentinel2.conf:/usr/local/etc/redis/sentinel.conf"
  sentinel3:
    image: redis                ## 镜像
    container_name: redis-sentinel-3
    ports:
    - "26381:26379"           
    command: redis-sentinel /usr/local/etc/redis/sentinel.conf
    volumes:
    - ./sentinel3.conf:/usr/local/etc/redis/sentinel.conf
networks:
  default:
    external:
      name: redis_sentinel-master

4. 启动Redis集群

cd /home/redis-sentinel/redis

docker-compose up -d

 

5. 启动哨兵集群

cd /home/redis-sentinel/sentinel 

docker-compose up -d

 

6. 查看集群健康情况

docker ps

  1. redis-cli -h 172.16.250.234 -p 6379 -a 123456

  2. 172.16.250.234:6379> info replication

发布了66 篇原创文章 · 获赞 31 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43272605/article/details/104144444