Redis 核心技术与实战
蒋德钧
中科院计算所副研究员
81696 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 53 讲
开篇词 (1讲)
实践篇 (28讲)
Redis 核心技术与实战
15
15
1.0x
00:00/00:00
登录|注册

32 | Redis主从同步与故障切换,有哪些坑?

建议调大cluster-node-timeout
实例响应心跳消息的超时时间
设置为no并绑定其他哨兵实例IP地址
限定哨兵实例访问权限
使用EXPIREAT/PEXPIREAT命令设置过期时间
使用Redis 3.2及以上版本
从库返回过期数据
过期数据未被删除
定期删除策略释放内存
惰性删除策略延迟删除
监控从库复制进度
保证良好网络环境
从库处理复杂命令阻塞
网络传输延迟
cluster-node-timeout配置项
protected-mode配置项
应对方法
读取过期数据原因
惰性删除策略和定期删除策略
应对方法
异步复制导致数据不一致
不合理配置项导致的服务挂掉
读取过期数据
主从数据不一致
Redis主从同步与故障切换

该思维导图由 AI 生成,仅供参考

你好,我是蒋德钧。
Redis 的主从同步机制不仅可以让从库服务更多的读请求,分担主库的压力,而且还能在主库发生故障时,进行主从库切换,提供高可靠服务。
不过,在实际使用主从机制的时候,我们很容易踩到一些坑。这节课,我就向你介绍 3 个坑,分别是主从数据不一致、读到过期数据,以及配置项设置得不合理从而导致服务挂掉。
一旦踩到这些坑,业务应用不仅会读到错误数据,而且很可能会导致 Redis 无法正常使用,我们必须要全面地掌握这些坑的成因,提前准备一套规避方案。不过,即使不小心掉进了陷阱里,也不要担心,我还会给你介绍相应的解决方案。
好了,话不多说,下面我们先来看看第一个坑:主从数据不一致。

主从数据不一致

主从数据不一致,就是指客户端从从库中读取到的值和主库中的最新值并不一致。
举个例子,假设主从库之前保存的用户年龄值是 19,但是主库接收到了修改命令,已经把这个数据更新为 20 了,但是,从库中的值仍然是 19。那么,如果客户端从从库中读取用户年龄值,就会读到旧值。
那为啥会出现这个坑呢?其实这是因为主从库间的命令复制是异步进行的
具体来说,在主从库命令传播阶段,主库收到新的写命令后,会发送给从库。但是,主库并不会等到从库实际执行完命令后,再把结果返回给客户端,而是主库自己在本地执行完命令后,就会向客户端返回结果了。如果从库还没有执行主库同步过来的命令,主从库间的数据就不一致了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Redis主从同步机制在实际应用中可能遇到的三个关键问题是主从数据不一致、读取到过期数据以及不合理配置项导致服务挂掉。主从数据不一致可能由于网络传输延迟或从库处理复杂命令而滞后执行同步命令,解决方法包括保证网络连接良好和开发外部程序监控复制进度。读取到过期数据问题是由Redis的过期数据删除策略引起的,建议使用Redis 3.2及以上版本避免读取到过期数据,并在业务应用中使用EXPIREAT/PEXPIREAT命令,避免读取到过期数据。另外,不合理配置项如protected-mode和cluster-node-timeout可能导致服务挂掉,建议将protected-mode配置项设置为no,并将bind配置项设置为其他哨兵实例的IP地址,以及将cluster-node-timeout调大。文章详细分析了这些问题,读者可以了解到在使用Redis主从同步机制时需要注意的关键技术细节,以及如何规避和解决这些常见问题。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Redis 核心技术与实战》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(35)

  • 最新
  • 精选
  • Kaito
    把 slave-read-only 设置为 no,让从库也能直接删除数据,以此来避免读到过期数据,这种方案是否可行? 我个人觉得这个问题有些歧义,因为尽管把 slave-read-only 设置为 no,其实 slave 也不会主动过期删除从 master 同步过来的数据的。 我猜老师想问的应该是:假设让 slave 也可以自动删除过期数据,是否可以保证主从库的一致性? 其实这样也无法保证,例如以下场景: 1、主从同步存在网络延迟。例如 master 先执行 SET key 1 10,这个 key 同步到了 slave,此时 key 在主从库都是 10s 后过期,之后这个 key 还剩 1s 过期时,master 又执行了 expire key 60,重设这个 key 的过期时间。但 expire 命令向 slave 同步时,发生了网络延迟并且超过了 1s,如果 slave 可以自动删除过期 key,那么这个 key 正好达到过期时间,就会被 slave 删除了,之后 slave 再收到 expire 命令时,执行会失败。最后的结果是这个 key 在 slave 上丢失了,主从库发生了不一致。 2、主从机器时钟不一致。同样 master 执行 SET key 1 10,然后把这个 key 同步到 slave,但是此时 slave 机器时钟如果发生跳跃,优先把这个 key 过期删除了,也会发生上面说的不一致问题。 所以 Redis 为了保证主从同步的一致性,不会让 slave 自动删除过期 key,而只在 master 删除过期 key,之后 master 会向 slave 发送一个 DEL,slave 再把这个 key 删除掉,这种方式可以解决主从网络延迟和机器时钟不一致带来的影响。 再解释一下 slave-read-only 的作用,它主要用来控制 slave 是否可写,但是否主动删除过期 key,根据 Redis 版本不同,执行逻辑也不同。 1、如果版本低于 Redis 4.0,slave-read-only 设置为 no,此时 slave 允许写入数据,但如果 key 设置了过期时间,那么这个 key 过期后,虽然在 slave 上查询不到了,但并不会在内存中删除,这些过期 key 会一直占着 Redis 内存无法释放。 2、Redis 4.0 版本解决了上述问题,在 slave 写入带过期时间的 key,slave 会记下这些 key,并且在后台定时检测这些 key 是否已过期,过期后从内存中删除。 但是请注意,这 2 种情况,slave 都不会主动删除由 *master 同步过来带有过期时间的 key*。也就是 master 带有过期时间的 key,什么时候删除由 master 自己维护,slave 不会介入。如果 slave 设置了 slave-read-only = no,而且是 4.0+ 版本,slave 也只维护直接向自己写入 的带有过期的 key,过期时只删除这些 key。 另外,我还能想到的主从同步的 2 个问题: 1、主从库设置的 maxmemory 不同,如果 slave 比 master 小,那么 slave 内存就会优先达到 maxmemroy,然后开始淘汰数据,此时主从库也会产生不一致。 2、如果主从同步的 client-output-buffer-limit 设置过小,并且 master 数据量很大,主从全量同步时可能会导致 buffer 溢出,溢出后主从全量同步就会失败。如果主从集群配置了哨兵,那么哨兵会让 slave 继续向 master 发起全量同步请求,然后 buffer 又溢出同步失败,如此反复,会形成复制风暴,这会浪费 master 大量的 CPU、内存、带宽资源,也会让 master 产生阻塞的风险。

    作者回复: 感谢Kaito同学的回复和详细分析!很赞! 我也解释下,到时出这道题的一个考虑出发点。 这道题我其实是想问大家,假设从库也能直接删除过期数据的话,是不是一个好方法。其实,是想提醒下同学们,主从复制中的增删改都需要在主库执行,即使从库能做删除,也不要在从库删除。否则会造成数据不一致。例如,假设主从库上都能做写操作的话,主从库上有a:stock的键,客户端A给主库发送一个SET命令,修改a:stock的值,客户端B给从库发送了一个SET命令,也修改a:stock的值,此时,相同键的值就不一样了。所以,让从库可以做写操作会造成主从数据不一致。

    2020-11-02
    11
    222
  • 老大不小
    老师,slave-serve-stale-data这个命令说的不清不楚的,对于初学者来说不明就里。 slave-serve-stale-data 解释:当一个slave与master失去联系时,或者复制正在进行的时候,slave应对请求的行为:1) 如果为 yes(默认值) ,slave 仍然会应答客户端请求,但返回的数据可能是过时,或者数据可能是空的在第一次同步的时候;2) 如果为 no ,在你执行除了 info 和 salveof 之外的其他命令时,slave 都将返回一个 "SYNC with master in progress" 的错误。 29、slave-read-only 解释:设置slave是否是只读的。从2.6版起,slave默认是只读的。
    2021-04-28
    2
    29
  • 思变
    老师您好,关于bind参数,不是设置redis能接受哪个本机网卡接入的连接吗?为什么要配置多个哨兵的IP呢
    2020-11-04
    2
    6
  • 杨逸林
    不是个好方法,如果不同客户端,去非当前从库读取数据时,就会出现缓存不一致的情况。
    2020-11-02
    6
  • 小白白不白
    EXPIRE、PEXPIRE和EXPIREAT三个命令都会转换成PEXPIREAT命令来执行,难道redis对于aof日志文件没有转为PEXPIREAT吗?
    2021-03-05
    3
    5
  • 刘浩
    slave-serve-stale-data配置了主从中断后,从库的逻辑 --no :从库只能应答INFO和SLAVEOF --yes默认 :正常应答 这样不知道对不对
    2020-11-13
    4
  • 赵茭茭
    主从复制 不是复制的是rdb吗 不是aof啊 这个和指令 带AT的还有效吗 还是我理解的有问题
    2020-12-07
    1
    3
  • Geek1254
    为什么不在主库删除过期key时给从库发送删除命令
    2021-06-20
    2
  • yu
    redis为何不把底层的expire实现成为expireAt,再发给从库进行同步,避免出现过期数据问题?
    2021-03-28
    2
    2
  • 零点999
    只有主库提供服务,从库只保证高可用
    2020-11-02
    2
收起评论
显示
设置
留言
35
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部