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 |
集群工作原理
服务端故障转移步骤:
- 发现主服务器已经进入客观下线状态。
- 对我们的当前纪元进行自增(详情请参考 Raft leader election ), 并尝试在这个纪元中当选。
- 如果当选失败, 那么在设定的故障迁移超时时间的两倍之后, 重新尝试当选。 如果当选成功, 那么执行以下步骤。
- 选出一个从服务器,并将它升级为主服务器。
- 向被选中的从服务器发送 SLAVEOF NO ONE 命令,它转变为主服务器。
- 通过发布与订阅功能, 将更新后的配置传播给所有其他 Sentinel , 其他 Sentinel 对它们自己的配置进行更新。
- 向已下线主服务器的从服务器发送 SLAVEOF 命令, 让它们去复制新的主服务器。
- 当所有从服务器都已经开始复制新的主服务器时, 领头 Sentinel 终止这次故障迁移操作。
客户端连接
- 先连接一个 Sentinel 实例
- 使用 SENTINEL get-master-addr-by-name master-name 获取 Redis 地址信息。
- 连接返回的 Redis 地址信息,通过 ROLE 命令查询是否是 Master。如果是,连接进入正常的服务环节。否则应该断开重新查询。
- (可选)客户端可以通过 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 机房)等。
参考资料
- http://www.yunweipai.com/archives/20444.html
- http://www.redis.cn/topics/sentinel.html
- https://segmentfault.com/a/1190000002685515
- https://segmentfault.com/a/1190000002680804
- https://lanjingling.github.io/2015/12/29/redis-sentinel-jedis-shizhan/
- http://www.cnblogs.com/xujishou/p/6511111.html
- https://dbarobin.com/2017/05/27/ha-of-redis/#36-redis-cluster
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于