【Redis】中的一些坑(二)——「主从复制」篇

上文中讲解了我们日常使用的一些命令,稍有不慎就会产生严重的影响,本文将继续讲解主从复制中的一些类似问题。

前景回顾: 【Redis】中的一些坑(一)——「常用命令」篇

3.1 主从复制导致数据丢失

首先,Redis 的主从复制采用「异步」方式进行。这就意味着如果 Master 突然宕机,可能会导致有部分数据还未同步到 Slave 的情况。

对于数据缓存的使用场景来说这没什么影响,数据丢了就丢了,但如果使用 Redis 来实现分布式锁,很可能因为数据丢失问题到时锁丢失,从而导致业务异常。

3.2 主从返回数据不一致

思考这么一个场景:存在一个已过期但还未被 Master 清理的数据,此时在 Slave 上查询这个数据会返回什么结果?

无非两种情况:一是正常返回数据,二是返回空。而具体是哪种结果就需要结合 Redis 版本执行的命令以及机器时钟三个因素来判断:

  • Redis 版本

在 Redis 3.2 版本之前,在 Slave 上查询一个 key 时,并不会判断这个 key 是否已过期,而是直接无脑返回给客户端结果。这其实算是 Redis 的一个 Bug,虽然在之后的版本以及修复,但修复的还「不够彻底」。

  • 执行的命令

Redis 3.2 虽然修复了 Slave 查询带过期时间 key 的 Bug,但却遗漏了一个命令EXISTS。即执行如 GET 等查询命令是,返回 nil,如果执行 EXISTS 命令时 Slave 依旧会返回该 key 还存在。

原因在于 EXISTS 与查询数据的命令使用的不是同一个方法。Redis 作者只在查询数据时增加了过期时间的校验,但 EXISTS 命令依旧没有这么做。直到 Redis 4.0.11 这个版本,Redis 才真正把这个遗漏的 Bug 完全修复。

  • 机器时钟

虽然高版本的 Redis 看似已经完美,但还是无法忽略一个关键因素,那就是 Master 和 Slave 实例的**「机器时钟」**。

无论是 Master 还是 Slave,在判断一个 key 是否过期时都是基于「本机时钟」来判断的,如果二者的机器时钟不一致,当然查询出来的数据也是不一致的。

3.3 主从切换导致缓存雪崩

这是上一个「主从数据不一致问题」的延伸。

假设 Slave 的机器时钟比 Master 走得「快」,而且是「快很多」。从 Slave 角度来看 Redis 中的数据存在「大量过期」。

如果此时因为各种原因进行了「主从切换」,把 Slave 提升为新的 Master后就会开始大量清理过期 key,此时就会导致以下结果:

  1. Master 大量清理过期 key,主线程发生阻塞,无法及时处理客户端请求;
  2. Redis 中数据大量过期,引发缓存雪崩。

当 Master 和 Slave 机器时钟严重不一致时,对业务的影响非常大!

3.4 主从大量数据不一致

当发现 Master 和 Slave 中数据大量不一致时,大概率是 Redis 集群中实例的 maxmemory 配置不同导致。我们知道 maxmemory 控制整个实例的内存使用上限,当实例实际使用内存超过这个上限,并且配置了淘汰策略,那么实例就开始淘汰数据。

如果 Salve 中的配置小于 Master 中的配置就有可能发生这样的情况。

当然,针对这个问题,Redis 官方在 5.0 版本中增加了一个配置项 replica-ignore-maxmemory,默认 yes。这个参数表示,尽管 Slave 内存超过了 maxmemory,也不会自行淘汰数据。

3.5 主从复制全量同步失败

我们知道 Slave 与 Master 进行全量数据同步时,Master 接收到 Slave 的全量同步请求后异步生成 RDB 文件返回给 Slave,从节点收到 RDB 文件后开始解析加载数据。

当数据文件很大时,Slave 的加载过程也将变得非常耗时,这里可能出现一种场景:Slave 加载 RDB 还未完成,Master 和 Slave 的连接却断开了,数据同步也失败了。之后又会发现 Slave 又发起了全量同步,同样地也在加载 RDB 时失败了,以此往复。

其实,这就是 Redis 的「复制风暴」问题。即主从全量同步失败,又重新开始同步,又同步失败,以此往复,恶性循环,持续浪费机器资源。

为什么会导致这种问题?

主从在全量同步数据期间 Master 接收到的写请求会先写到主从「复制缓冲区」中,这个缓冲区的「上限」是 slave client-output-buffer-limit 配置决定的。当 Slave 加载 RDB 太慢时,就会导致 Slave 无法及时消费「复制缓冲区」中的数据,这就导致了复制缓冲区「溢出」。

为了避免内存持续增长,此时的 Master 会「强制」断开 Slave 的连接,这时全量同步就会失败。

之后,同步失败的 Slave 又会「重新」尝试全量同步,进而又陷入上面描述的问题中,以此往复,恶性循环,这就是所谓的「复制风暴」。

如何解决复制风暴问题?

  1. Redis 实例不要太大,避免过大的 RDB;
  2. 合理配置「复制缓冲区」配置,降低全量同步失败的概率。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿周周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值