redis哨兵+主从
Sentinel介绍
Redis Sentinel 是社区版本推出的原生高可用解决方案,其部署架构主要包括两部分:Redis Sentinel 集群和 Redis 数据集群。
其中 Redis Sentinel 集群是由若干 Sentinel 节点组成的分布式集群,可以实现故障发现、故障自动转移、配置中心和客户端通知。Redis Sentinel 的节点数量要满足 2n+1(n>=1)的奇数个。
Sentinel领导者选举
原因:只有一个sentinel
节点完成故障转移
选举:通过sentinel is-master-down-by-addr
命令都希望成为领导者
- 每个做主观下线的
sentinel
节点向其他sentinel
节点发送命令,要求将它设置为领导者 - 收到命令的
sentinel
节点如果还没有同意过其他semtinel
节点发送的命令,那么将同意该请求,否则拒绝 - 如果该
sentinel
节点发现自己的票数已经超过sentinel
集合半数并且超过quorum
,那么它将成为领导者。 - 如果此过程中多个
sentinel
节点成为了领导者,那么将等待一段时间重新进行选举
故障转移
- 从
slave
节点中选出一个“合适的”节点作为新的master
节点 - 对上述的
slave
节点执行“slaveof no one
”命令使其成为master
节点 - 向剩余的
slave
节点发送命令,让它们成为新master
节点的slave
节点,复制规则和parallel-syncs
参数一样 - 更新对原来的
master
节点配置为slave
,并保持着对其“关注”,当恢复后命令他去复制新的master
节点
那么,如何选择“合适”的slave
节点呢?
- 选择
slave-priority
(slave
节点优先级)最高的slave
节点,如果存在则返回,不存在则继续。 - 选择复制偏移量最大的
slave
节点(复制得最完整),如果存在则返回,不存在则继续 - 选择
run_id
最小的slave
节点(最早的节点)
主观下线和客观下线
对于之前的Sentinel
配置文件中有两条配置:
监控master redis
节点,这里是当超过两个sentinel
认为master
挂了,则认为master
挂了。
sentinel monitor <masterName> <masterIp> <msterPort> <quorum> sentinel monitor mymaster 127.0.0.1 6379 2
这里是每秒sentinel
都会去Ping
周围的master redis
,超过30秒没有任何响应,说明其挂了。
sentinel down-after-milliseconds <masterName> <timeout> sentinel down-after-milliseconds mymaster 300000
主观下线
每个sentinel
节点对Redis
节点失败的“偏见”
这是一种主观下线。因为在复杂的网络环境下,这个sentinel
与这个master
不通,但是master
与其他的sentinel
都是通的呢?所以是一种“偏见”
依靠定时:每秒去ping一下周围的sentinel
和redis
。对于slave redis
,可以使用这个主观下线,因为他不需要进行故障转移。
客观下线
客观下线:所有sentinel
节点对master Redis
节点失败“达成共识”(超过quorum
个则统一)
依靠定时:每两秒,sentinel
之间进行“商量”,传递的消息是:sentinel is-master-down-by-addr
对于master redis
的下线,必须要达成共识才可以,因为涉及故障转移,仅仅依靠一个sentinel
判断是不够的。
脑裂问题
redis的集群脑裂是指因为网络问题,导致redis master节点跟redis slave节点和sentinel集群处于不同的网络分区,此时因为sentinel集群无法感知到master的存在,所以将slave节点提升为master节点。此时存在两个不同的master节点,就像一个大脑分裂成了两个。
解决方案
redis的配置文件中,存在两个参数
min-slaves-to-write 1
min-slaves-max-lag 10
-
第一个参数表示连接到master的最少slave数量
-
第二个参数表示slave连接到master的最大延迟时间
-
按照上面的配置,要求至少1个slave节点,且数据复制和同步的延迟不能超过10秒,否则的话master就会拒绝写请求,配置了这两个参数之后,如果发生集群脑裂,原先的master节点接收到客户端的写入请求会拒绝,就可以减少数据同步之后的数据丢失。
注意:较新版本的redis.conf文件中的参数变成了
min-replicas-to-write 1 min-replicas-max-lag 10
分布式锁
锁失效
master节点加锁后,未复制到slave节点,master发生故障转移,导致多个client获取到同一把锁,丧失锁安全权
- 客户端 A 从 Master 节点获取锁。
- Master 节点出现故障,主从复制过程中,锁对应的 key 没有同步到 Slave 节点。
- Slave升 级为 Master 节点,但此时的 Master 中没有锁数据。
- 客户端 B 请求新的 Master 节点,并获取到了对应同一个资源的锁。
- 出现多个客户端同时持有同一个资源的锁,不满足锁的互斥性。
解决方案
使用RedLock,需要奇数个独立的Redis Sentinel集群,通过对多数集群加锁成功才算加锁成功,需要根据不同业务做取舍,是否使用这种方式。
死锁
锁未释放,客户端宕机。
解决方案
原子操作设置过期时间;获取锁设置超时时间。
锁续期
守护线程,自从续期(watch dog)
优缺点
优点
-
Redis Sentinel 集群部署简单;
-
能够解决 Redis 主从模式下的高可用切换问题;
-
很方便实现 Redis 数据节点的线形扩展,突破 Redis 自身单线程瓶颈;
-
可以实现一套 Sentinel 监控一组 Redis 数据节点或多组数据节点。
缺点
-
部署相对 Redis 主从模式要复杂一些,原理理解更繁琐;
-
资源浪费,Redis 数据节点中 slave 节点作为备份节点不提供服务;
-
Redis Sentinel 主要是针对 Redis 数据节点中的主节点的高可用切换,对 Redis 的数据节点做失败判定分为主观下线和客观下线两种,对于 Redis 的从节点有对节点做主观下线操作,并不执行故障转移。
-
不能对从节点进行故障转移以至于不能解决读写分离问题,实现起来相对复杂。
参考资料
高可用:https://blog.51cto.com/u_13294304/3360074
Sentinel Leader选举:https://cloud.tencent.com/developer/article/1021467
RedLock:https://redis.io/docs/reference/patterns/distributed-locks/
Redis锁:http://kaito-kidd.com/2021/06/08/is-redis-distributed-lock-really-safe/