Redis sentinel 高可用 (HA) 方案调研

本贴最后更新于 2080 天前,其中的信息可能已经时移世易

Redis Sentinel 高可用(HA)方案

Redis-Sentinel 是 Redis 官方推荐的高可用性(HA)解决方案,当用 Redis 做 Master-slave 的高可用方案时,假如 master 宕机了,Redis 本身(包括它的很多客户端)都没有实现自动进行主备切换,而 Redis-sentinel 本身也是一个独立运行的进程,它能监控多个 master-slave 集群,发现 master 宕机后能进行自动切换。

专业术语

  • 主观下线(Subjectively Down, 简称 SDOWN)指的是单个 Sentinel 实例对服务器做出的下线判断。
  • 客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的服务器下线判断。(一个 Sentinel 可以通过向另一个 Sentinel 发送 SENTINELis-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线.)

集群架构

集群逻辑部署图

  • 机器列表 PS:这里的机器是再本地 MAC 机上用 virtualBox 做的虚机,系统均为 centOS7
机器 IP CPU 内存 硬盘 端口及初始服务
192.168.99.101 2 核 2g 30G 6379:redis 主
26379:sentinel
192.168.99.102 2 核 2g 30G 6379:redis 从
26379:sentinel
192.168.99.103 2 核 2g 30G 6379:redis 从
26379:sentinel

集群工作原理

服务端故障转移步骤:

  1. 发现主服务器已经进入客观下线状态。
  2. 对我们的当前纪元进行自增(详情请参考 Raft leader election ), 并尝试在这个纪元中当选。
  3. 如果当选失败, 那么在设定的故障迁移超时时间的两倍之后, 重新尝试当选。 如果当选成功, 那么执行以下步骤。
  4. 选出一个从服务器,并将它升级为主服务器。
  5. 向被选中的从服务器发送 SLAVEOF NO ONE 命令,它转变为主服务器。
  6. 通过发布与订阅功能, 将更新后的配置传播给所有其他 Sentinel , 其他 Sentinel 对它们自己的配置进行更新。
  7. 向已下线主服务器的从服务器发送 SLAVEOF 命令, 让它们去复制新的主服务器。
  8. 当所有从服务器都已经开始复制新的主服务器时, 领头 Sentinel 终止这次故障迁移操作。

客户端连接

  1. 先连接一个 Sentinel 实例
  2. 使用 SENTINEL get-master-addr-by-name master-name 获取 Redis 地址信息。
  3. 连接返回的 Redis 地址信息,通过 ROLE 命令查询是否是 Master。如果是,连接进入正常的服务环节。否则应该断开重新查询。
  4. (可选)客户端可以通过 SENTINEL sentinels 来更新自己的 Sentinel 实例列表。

集群配置

Redis 配置说明

vim redis.conf 默认配置需要添加或者修改如下配置,其他参数酌情配置即可,这里使用了默认配置

bind 192.168.99.101

# 在slave节点才配置,master不用配置
slaveof 192.168.99.101 6379 
requirepass "000000"
masterauth "000000"

# 写入命令同步额外写入一个从服务器
min-slaves-to-write 1 
min-slaves-max-lag 10 

Sentinel 配置说明

vim sentinel.conf
# 以后台进程模式运行
daemonize yes
# sentinel 绑定端口
port 26379
# sentinel 绑定的主机 ip
bind 192.168.99.101

# redis-master是主数据的别名,考虑到故障恢复后主数据库的地址和端口号会发生变化,哨兵提供了命令可以通过别名获取主数据库的地址和端口号。   
sentinel monitor redis-master 192.168.99.103 6379 2

# 192.168.99.103 6379 为初次配置时主数据库的地址和端口号,当主数据库发生变化时,哨兵会自动更新这个配置,不需要我们去关心。
# 2,该参数用来表示执行故障恢复操作前至少需要几个哨兵节点同意,一般设置为N/2+1(N为哨兵总数)。
 
# master在多少秒内无反应哨兵会开始进行master-slave间的切换,使用“选举”机制
sentinel down-after-milliseconds redis-master 3000

# 选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长
sentinel parallel-syncs redis-master 1 

# 指定Sentinel检测到该监控的Redis实例failover时调用的报警脚本。脚本被允许执行的最大时间为60秒,超过这个时间脚本会被kill。该配置项可选,但线上系统建议配置。
sentinel notification-script redis-master /usr/local/redis/notify.sh 

# 指定Sentinel failover之后重配置客户端时执行的脚本,该配置项可选,但线上系统建议配置。
sentinel client-reconfig-script redis-master /usr/local/redis/failover.sh 

# 当Master设置了密码时,Sentinel连接Master和Slave时需要通过设置参数auth-pass配置相应密码。
sentinel auth-pass redis-master 12345678 
# log文件全路径
logfile "/var/log/redis/redis-sentinel.log" 

集群部署手册

配置完 Redis 和 Sentinel 之后,按顺序启动各个角色。启动顺序如下:Master->Slave->Sentinel,要确保按照这个顺序依次启动。

安装 redis

mkdir /data/soft
cd /data/soft
curl -o redis-3.2.9.tar.gz http://download.redis.io/releases/redis-3.2.9.tar.gz
tar -zxvf redis-3.2.9.tar.gz
cd redis-3.2.9
make

mkdir -p /usr/local/redis && cp ./src/redis-server /usr/local/redis/ && cp ./src/redis-sentinel /usr/local/redis/ && cp ./src/redis-cli /usr/local/redis/

配置

配置/redis.conf 以及/sentinel.conf

启动 Redis

依次启动三台机器的 redis 实例

cd ${REDIS_CONF_PATH}
nohup /usr/local/redis/redis-server ./redis-3.2.9/redis.conf &

启动 sentinel

cd ${REDIS_CONF_PATH}
nohup /usr/local/redis/redis-sentinel ./redis-3.2.9/sentinel.conf &

Sentinel 信息检测

redis-cli -p 26379 -h 192.168.2.210 INFO Sentinel

输出

Sentinel

sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=redis-master,status=ok,address=192.168.99.103:6379,slaves=2,sentinels=3     

故障测试

这里模拟的场景是,在 java 客户端不断做写入读取操作,过程中停止 master 的实例,观察集群的自愈能力.
2017-07-07 14:13:27,362 [main] INFO com.td.dx.fin.TestJedis - [key_2200][value_2200]
2017-07-07 14:13:27,468 [main] INFO com.td.dx.fin.TestJedis - [key_2300][value_2300]
2017-07-07 14:13:27,574 [main] INFO com.td.dx.fin.TestJedis - [key_2400][value_2400]
2017-07-07 14:13:27,682 [main] ERROR com.td.dx.fin.TestJedis - error

    ..........
    
    at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:101)
    ... 4 common frames omitted
2017-07-07 14:13:31,653 [main] INFO  com.td.dx.fin.TestJedis - [key_2500][value_2500]                                                                             
2017-07-07 14:13:31,758 [main] INFO  com.td.dx.fin.TestJedis - [key_2600][value_2600]
2017-07-07 14:13:31,864 [main] INFO  com.td.dx.fin.TestJedis - [key_2700][value_2700]
2017-07-07 14:13:31,970 [main] INFO  com.td.dx.fin.TestJedis - [key_2800][value_2800]
2017-07-07 14:13:32,074 [main] INFO  com.td.dx.fin.TestJedis - [key_2900][value_2900]
2017-07-07 14:13:32,179 [main] INFO  com.td.dx.fin.TestJedis - [key_3000][value_3000]

从客户端的异常来分析,服务端的故障恢复耗时 4s.在服务端的 down-after-milliseconds 参数配置的是 3s,也就是说 failover 所需时间大致在秒级.

特别说明

  • Redis Sentinel 严重依赖计算机的时间功能,需要做好服务器时间同步
  • 对于一个最小集群,Redis 应该是一个 Master 带上两个 Slave,并且开启下列选项:
    min-slaves-to-write 1 # 写入命令同步写入一个从服务器 min-slaves-max-lag 10 # 写入slave的延时值,如果超过10秒,将拒绝写入操作
  • Slave 可以适当设置优先级,除了 0 之外(0 表示永远不提升为 Master),越小的优先级,越有可能被提示为 Master。如果 Slave 分布在多个机房,可以考虑将和 Master 同一个机房的 Slave 的优先级设置的更低以提升他被选为新的 Master 的可能性。
  • 考虑到可用性和选举的需要,Sentinel 进程至少为 3 个,推荐为 5 个。如果有网络分区,应当适当分布(比如 2 个在 A 机房, 2 个在 B 机房,一个在 C 机房)等。

参考资料

  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 247 回帖 • 210 关注
  • 集群
    29 引用 • 65 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...