持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
引言
上期我们讲了如何搭建主从集群实现高并发场景下的业务需求,对于主从集群模式,如果从库发生了故障,还有主库和其它的从库可以接收请求,但是如果主库挂了,就不能进行正常的数据写入并且数据同步也不能正常的进行。要避免这种问题就需要使用Redis的哨兵机制。今天我们跟着b站黑马的视频学习如何使用Redis哨兵(Sentinel)机制来实现主从集群的自动故障恢复。
什么是哨兵机制
哨兵(sentinel) 是一个分布式系统,哨兵节点是特殊的 Redis 服务,不提供读写,主要来监控 Redis 中的实例节点,当发现主节点异常时,会重新选出主节点,并通知其他节点去新的主节点进行数据同步。
于是,Redis哨兵机制有三个核心功能:监控,自动故障恢复,通知。
- 监控:一般使用心跳机制通过不间断的发出 PING 命令,检测节点是否正常运行
- 自动故障恢复:当有master发生故障,Sentinel会随机抽取一个slave提升为master。当故障实例恢复后也以新的master为主。
- 通知:Sentinel充当Redis客户端的服务发现来源,当主节点发生故障并推选出新的master时,会将信息告知其他节点。
在实际场景中,Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
- 主观下线:如果有一个sentinel节点发现某实例未在规定时间内响应,则认为该实例主观下线。
- 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
选举新的master节点遵循的原则
- 判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则先排除该slave节点
- 判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
- 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
- 判断slave节点的运行id大小,id越小优先级越高
通过以上机制如果还存在几个同时满足条件的节点,则由Sentinel节点推选新的master节点。
推选出新的master节点之后,实现故障转移
- sentinel给备选的slave节点发送slaveof no one命令,让该节点成为master
- sentinel给所有其它slave发送slaveof 127.0.0.1 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
- sentinel将故障的主节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
配置Sentinel
# 指定端口号
port 27001
# 指定ip地址
sentinel announce-ip "127.0.0.1"
# 指定主节点
sentinel monitor mymaster 127.0.0.1 7001 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
dir "/home/redis-stable/sentinel/s1"
在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。
RedisTemplate的哨兵模式
- 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 在配置文件application.yml中指定sentinel的相关配置信息
spring:
redis:
sentinel:
master: mymaster # 指定master名称
nodes: # 指定redis-sentinel集群信息
- 127.0.0.1:27001
- 127.0.0.1:27002
- 配置主从读写分离
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
/*ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择:
MASTER:从主节点读取
MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
REPLICA:从slave(replica)节点读取
REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master*/
}
总结
Redis的Sentinel机制仅仅解决了 高可用 的问题,对于 主节点 单点写入和单节点无法扩容等问题,还需要引入 Redis Cluster 集群模式 予以解决。