Redis系列之Redis Sentinel

概述

Redis主从集群,一主多从模式,包括一个Master节点和多个Slave节点。Master负责数据的读写,Slave节点负责数据的查询。Master上收到的数据变更,会同步到Slave节点上实现数据的同步。通过这种架构实现可以Redis的读写分离,提升数据的查询性能。

主从集群不提供容错和恢复功能,一旦Master节点宕机,不会自动选出新的Master,导致后续客户端所有写请求直接失败。

引入

Redis引入Redis Sentinel,即哨兵机制,哨兵会监控Redis主从集群节点的状态,当Master节点出现故障,会自动从剩余的Slave节点中选择新的Master:

  • 一旦监控发现redis主节点失效,将选举出一个哨兵节点作为领导者;
  • sentinel的领导者从剩余的从redis节点中选出一个redis节点作为新的主redis节点对外服务。

Redis Sentinel用于实现Redis集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,可以监控一个或者多个主从集群:

  • 故障转移时,判断一个Master节点是否宕机,需要大部分的哨兵都同意才行,涉及到分布式选举的问题
  • 即使部分哨兵节点挂掉,哨兵集群还是能正常工作

Redis Sentinel,能够自动完成故障发现和故障转移并通知应用方,具备如下功能:

  • 集群监控:负责监控Master和Slave进程是否正常工作;
  • 消息通知:如果某个Redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员;
  • 故障转移:如果Master节点宕机,会自动转移到Slave节点上;
  • 配置中心:如果发生故障转移,通知客户端新的Master地址;

另外

  • 哨兵至少需要3个实例,来保证自己的健壮性
  • 哨兵 + Redis主从的部署架构,是不保证数据零丢失的,只能保证Redis集群的高可用性
  • 对于哨兵 + Redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练

安装

安装Redis Sentinel之前,需要确保已经成功安装至少一套Redis主从集群,即集群启动成功。生产环境里,Redis主从集群节点和Redis Sentinel集群节点最好是不同的IP节点。为了满足过半原则,Redis Sentinel至少需要3台节点。

安装时,提前创建好sentinel运行时需要的几个文件夹:conf、data、log,以及sentinel.conf配置文件,仅供参考:

ini 复制代码
port 26379
daemonize yes
logfile "26379.log"
# Sentinel实例的目录
dir "/data/redis/sentinel/"
# 格式:sentinel [option_name] [master_name] [ip] [port] [quorum],sentinel监控的master为mymaster,最后的2表示当集群中有2个sentinel认为master不可用时,才真正认为该master不可用,即客观下线
sentinel monitor mymaster 10.215.20.7 6379 2
# sentinel会向master发送心跳PING来确认master是否存活,如果master在down-after-milliseconds内不回应PONG或回复错误消息,则这个sentinel会主观地认为这个master不可用
sentinel down-after-milliseconds master 30000
# 在发生failover主备切换时,指定最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为1来保证每次只有一个slave处于不能处理命令请求的状态
sentinel parallel-syncs mymaster 1
# failover过期时间,当failover开始后,在此时间内仍然没有触发任何failover操作,当前sentinel将会认为此次failoer失败,单位为秒
sentinel failover-timeout mymaster 180000

以Redis用户执行启动命令:sudo -u redis /opt/redis/bin/redis-sentinel /data/redis/sentinel/conf/sentinel.conf,从启动日志可判断Sentinel集群是否正常启动。

在节点执行info sentinel命令,查看sentinel的信息。

心跳检查

Sentinel通过三个定时任务来检测各个节点是否存活及出现超时:

  1. 每隔10秒,每个哨兵节点会向已知的主从节点发送info命令获取最新的主从架构。哨兵节点通过解析响应信息,获取当前Redis数据节点的最新拓扑结构。如果是新增节点,哨兵就会与其建立连接;
  2. 每隔2秒,哨兵节点都会向主从节点的__sentinel__:hello频道发送自己的信息。两个目的:
    • 发现新的哨兵节点
    • 哨兵节点之间交换主节点的状态,作为后面客观下线以及领导者选择的依据
  3. 每隔1秒,哨兵会给每个主从节点、其他哨兵节点发送PING命令。此定时任务是哨兵心跳机制中的核心,它涉及到Redis数据节点的运行状态监控,哨兵领导者的选举等细节操作。当哨兵节点发送PING命令后,若超过down-after-milliseconds后,没有收到有效回复(错误的回复不是有效回复),当前哨兵节点会认为该节点主观下线。

发送的消息内容格式为:
<哨兵地址>,<哨兵端口>,<哨兵运行ID>,<哨兵配置版本>,<主数据库名称>,<主库地址>,<主库端口>,<主库配置版本>

自动发现机制

哨兵互相之间的发现,是通过Redis的pub/sub系统实现的,每个哨兵都会往__sentinel__:hello这个channel里发送消息,此时其他所有哨兵都可以消费这个消息,并感知到其他哨兵的存在。

每隔两秒钟,每个哨兵都会往自己监控的某个Master+Slaves对应的__sentinel__:hello channel里发送一个消息,内容是自己的host、ip和Run ID,还有对这个Master的监控配置。

每个哨兵也会去监听自己监控的每个Master+Slaves对应的__sentinel__:hello channel,然后去感知到同样在监听这个Master+Slaves的其他哨兵的存在。

每个哨兵还会跟其他哨兵交换对Master的监控配置,互相进行监控配置的同步。

Slave配置的自动纠正

哨兵会负责自动纠正Slave的一些配置,如Slave如果要成为潜在的 Master候选人,哨兵会确保Slave复制现有Master的数据;如果Slave连接到错误的Master上,比如故障转移之后,那么哨兵会确保它们连接到正确的Master上。

下线

有主观下线和客观下线两种。

主观下线

Subjectively Down,缩写sdown,也叫主观宕机。

在第三个定时任务中,每隔1秒哨兵节点会向每个Redis数据节点发送PING命令,若超过down-after-milliseconds设定的时间没有收到响应,则会对该节点做失败判定,这种行为叫做主观下线。是某一个哨兵节点的判断,存在误判概率。

客观下线

Objectively Down,缩写sdown,也叫客观宕机。

当哨兵节点判定一个主节点为主观下线后,则会通过sentinelis-master-down-by-addr命令询问其他哨兵节点对该主节点的状态,当收到quorunm个其他哨兵节点认为主节点也存在问题的应答后,这时该哨兵节点会对主节点做客观下线的决定。

客观下线是针对主机节点,如果主观下线的是从节点或者其他哨兵节点,则不会进行后面的客观下线和故障转移。

哨兵选举

当主节点客观下线时,需要选举出一个哨兵节点做为领导者,以完成后续选出新的主节点的工作。基于Raft算法的哨兵选举的主要流程:

  1. 每一个做主观下线的哨兵节点都有成为领导者的可能,他们会向其他哨兵节点发送sentinel is-master-down-by addr,要求将它设置为领导者;
  2. 每个哨兵节点在收到一个sentinel is-master-down-by addr命令时,只允许给第一个节点投票,其他节点的该命令都会被拒绝;
  3. 如果某个哨兵节点收到半数以上的同意票,则成为哨兵领导者;
  4. 如果该过程有多个哨兵成为领导者,则将等待一段时间重新进行下一轮选举,直到有且只有一个哨兵节点成为领导者为止;

一般来说,哨兵选举的过程很快,谁先完成客观下线,一般就能成为领导者。

配置传播:哨兵完成切换之后,会在自己本地更新生成最新的Master配置,并更新Version版本号,同步给其他哨兵,通过pub/sub消息机制。

故障转移

Failover,也叫故障切换。

不管是Redis Master还是Slave节点,都必须在配置中指定一个Slave优先级。如果某个Slave优先级配置为0,则永远不会被选为Master,但依然会从Master那里复制数据。

如果一个Master被认为客观下线,且majority数量的哨兵都允许主备切换,则某个哨兵就会执行主备切换操作,此时首先要选举Slave作为Master,会考虑Slave的一些信息:

  • 过滤掉不健康的Slave节点(主观下线、断线)、5秒内没有回复过哨兵节点PING响应的Slave节点
  • 跟Master断开连接的时长
  • Slave优先级
  • 复制offset
  • Run ID

如果一个Slave跟Master断开连接的时间已经超过down-after-milliseconds的10倍,外加Master宕机的时长,则此Slave节点就被认为不适合选举为Master:(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

接下来会对Slave进行排序:

  • 按照Slave优先级进行排序,Slave节点配置的priority越低,优先级越高;
  • 如果Slave节点priority相同,则看复制offset,哪个Slave复制越多的数据,即offset越靠后(数据越完整,此处注意存在数据丢失可能性),优先级就越高;
  • 如果上面两个条件都相同,则选择一个Run ID较小的那个Slave;

当某个哨兵节点通过选举成为领导者,就要承担起故障转移的工作,具体步骤:

  1. 从从节点列表中选择一个节点作为新的主节点
  2. 在新的主节点上执行slaveof no one,让其变成主节点
  3. 向剩余的从节点发送slaveof命令,让它们成为新主节点的从节点
  4. 哨兵节点集合会将原来的主节点更新为从节点,当其恢复之后命令它去复制新的主节点的数据

缺点

Redis Sentinel集群存在的缺点:

  • 配置复杂性:Redis Sentinel集群相对复杂,需要细致的配置和调优,尤其是在大型集群中;
  • 一致性问题:在网络分区或某些情况下,可能会出现脑裂问题,即集群中的一部分认为主节点是可用的,而另一部分认为主节点已经失效,导致多个主节点同时存在;
  • 故障检测延迟:Sentinel对主节点故障的检测和恢复有一定延迟,可能会在检测到故障和完成故障转移之间有一段时间的服务中断;
  • 有限的高可用性:Sentinel集群本身也可能出现故障,特别是在网络环境不稳定时;
  • 主从复制延迟:从节点的数据同步是异步的,在主节点故障转移过程中,可能会有数据丢失或不一致的情况;
  • 资源开销:搭建Sentinel集群需要额外的资源,且每个Sentinel实例都会定期对Redis节点进行健康检查,增加一定的网络和计算开销;
  • 对网络环境依赖高:Sentinel集群对网络环境要求较高,网络延迟和抖动可能会影响Sentinel的故障检测和选举过程,进而影响故障转移的效率和准确性;
  • 手动干预需求:尽管Sentinel提供自动故障转移功能,但在某些复杂情况下,仍然可能需要人工干预来解决问题,如在处理脑裂情况或调整集群配置时。

数据丢失

此处对上面提到的数据丢失加以详述。Redis哨兵主备切换过程中可能会导致数据丢失的的两种情况:

  • 异步复制:从Master到Slave的复制是异步的,可能有部分数据还没复制到Slave,Master宕机,这部分数据可能发生丢失
  • 脑裂:Master节点突然脱离正常的网络,跟其他Slave机器不能连接,但实际上Master还在运行。此时哨兵可能会认为Master宕机并开启选举,将其他Slave切换成Master。此时集群里就会有两个Master,即所谓的脑裂。此时虽然某个Slave被切换成Master,但客户端可能还没来得及切换到新的Master,继续向旧Master写数据。因此旧Master再次恢复时,会被作为一个Slave挂到新的Master上去,自己的数据会清空,重新从新的Master复制数据。而新Master并没有客户端写入的这一部分数据,发生数据丢失。

优化方案

做如下配置:

复制代码
# 至少有1个Slave
min-slaves-to-write 1
# 数据复制和同步的延迟不能超过10秒
min-slaves-max-lag 10

如果说一旦所有的Slave,数据复制和同步的延迟都超过10秒钟,此时Master就不会再接收任何请求。显然,这个做法并不好,会阻塞客户端提交的写请求。

  • 减少异步复制数据的丢失
    min-slaves-max-lag配置可以确保,一旦Slave复制数据和ack延时太长,就认为可能Master宕机后损失的数据太多,那么就拒绝写请求,这样可以把Master宕机时由于部分数据未同步到Slave导致的数据丢失降低的可控范围内。

  • 减少脑裂的数据丢失

    如果一个Master出现脑裂,跟其他Slave丢失连接,那么上面两个配置可以确保说,如果不能继续给指定数量的Slave发送数据,而且Slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求。因此在脑裂场景下,最多就丢失10秒的数据。

但是在线扩容的问题还是没有解决。

参考

相关推荐
Kagol8 小时前
macOS 和 Windows 操作系统下如何安装和启动 MySQL / Redis 数据库
redis·后端·mysql
hzulwy9 小时前
Redis常用的数据结构及其使用场景
数据库·redis
ashane131410 小时前
Redis 哨兵集群(Sentinel)与 Cluster 集群对比
redis
Y第五个季节11 小时前
Redis - HyperLogLog
数据库·redis·缓存
Justice link12 小时前
企业级NoSql数据库Redis集群
数据库·redis·缓存
爱的叹息15 小时前
Spring Boot 集成Redis 的Lua脚本详解
spring boot·redis·lua
morris1311 天前
【redis】redis实现分布式锁
数据库·redis·缓存·分布式锁
爱的叹息1 天前
spring boot集成reids的 RedisTemplate 序列化器详细对比(官方及非官方)
redis
weitinting1 天前
Ali linux 通过yum安装redis
linux·redis
纪元A梦1 天前
Redis最佳实践——首页推荐与商品列表缓存详解
数据库·redis·缓存