Redis 复制运维及优化

## 前言

在理解了 Redis 的复制原理之后,一起来看看 Redis 复制有哪些坑,以及如何避免。


规避全量复制

全量复制是一个非常耗费资源的操作,从一个经验来看,一个 6GB 的从节点发起全量复制的总耗时在 2 分钟所有,感受一下。

因此当数据量达到一定规模以后,由于全量复制涉及到多次持久化操作和网络数据传输,这期间会消耗大量 CPU,内存,硬盘,带宽,所以除了第一次全量复制不可避免,应当尽力避免其他场景发生的全量复制。

全量复制通常有 3 种情况:第一次全量复制,节点运行 ID 不匹配,复制积压缓冲区不足。

第一次全量复制:由于是第一次建立复制,从节点没有数据,所以这个操作不可避免。当对数据量较大,网络流量较高的主节点添加从节点时,建议在低峰时进行操作,或者尽量避免规避大数据量的 Redis 节点。

节点运行 ID 不匹配:当主从关系建立后,从节点会保存主节点的运行 ID,如果此时主节点因故障重启,那么他的运行 ID 会改变,从节点发现主节点运行 ID 不匹配时,会认为这是一个新的主节点,从而进行全量复制,并清空之前的数据。对于这种情况,应当从架构上进行规避,比如提供故障转移功能:当主节点发生故障后,手动提升从节点,或者采用支持自动故障转移的哨兵或集群方案。

复制积压缓冲区不足:当主从节点网络中断后,从节点再次连上主节点时会发送 psync {runId} {offset} 命令请求部分复制,如果请求的偏移量不再主节点的积压缓冲区内,则无法提供给从节点数据,因此部分复制会退化成全量复制,针对这种情况,需要根据网络中断时长,写命令数据量,分析出合理的缓冲区大小,然后修改 repl_backlog_size 配置。从而避免因复制积压缓冲区不足造成的全量复制。


规避复制风暴

复制风暴指的是,大量从节点向同一个 Redis 主节点或者同一台物理机发起全量复制,此时将导致被发起的主节点或机器产生大量开销,例如 CPU,内存,硬盘,带宽等。

我们可以通过分析场景,然后做合理的规避。

单主节点复制风暴:单主节点复制风暴指的是,一个主节点挂载多个从节点,当主节点重启恢复后,从节点会发起全量复制流程,这时主节点就会为从节点创建 RDB 快照,如果在快照创建完毕之前,有多个从节点都尝试与主节点记性全量同步,那么其他从节点将共享这份 RDB 快照。这点 Redis 做了优化。有效避免了创建多个快照。但是,同时向多个从节点发送 RDB 文件,仍然会导致网络带宽消耗严重,造成主节点的延迟变大。极端情况导致主从连接断开,导致复制失败。

解决方案首先可以减少主节点上挂载从节点的数量,或者采用树状结构。

单机器:由于 Redis 是单线程架构,所以,通常会在一台物理机上部署多个实例,如果这台机器出现故障或网络长时间中断,当他重启恢复时,会有大量从节点针对这台机器的主节点进行全量复制,会造成当前机器带宽耗尽。
优化方案:1. 应当把主节点尽量分散在多台机器上,避免在单台机器上部署过多的主节点。2. 当主节点所在机器故障后提供故障恢复转移机制,避免机器恢复后进行密集的全量复制。

读写分离

  1. 数据延迟
    Redis 复制数据的延迟由于异步特性是无法避免的,延迟多少取决于网络带宽和命令阻塞情况,例如出现刚刚在主节点写入数据后立刻在从节点上读取可能获取不到。

而具体延迟多少,可以通过 info replication 的 offset 指标进行排查。

也可以通过监控程序通知客户端,让客户端换一个节点获取数据。

建议在进行读写分离架构前了解一下 Redis Cluster。

  1. 读到过期数据

当主节点存到大量设置超时的数据,Redis 内部需要维护过期数据删除策略,删除策略主要由 2 种:惰性删除和定时删除。

惰性删除:每次访问数据的时候,主节点都检查是否过期,如果过期则执行 del 命令,然后异步发送 del 命令给从节点,注意:从节点永远不会主动删除数据,这也是为了保证数据一致性。

定时删除:Redis 主节点在内部定时任务会循环采样一定数量的键,当发现采样的键过期时执行 del 命令,之后再同步给从节点。
如果此时大量数据超时,定时任务速度更不上,且主节点没有被访问,也就无法执行 del,进而从节点也无法执行 del。客户端就会读到从节点的过期数据。Redis 3.2 版本已经解决了这个问题,在从节点读取数据时,会检查键的过期时间。

  1. 从节点故障问题

对于从节点的故障问题,需要在客户端维护一个可用从节点可用列表,当从节点故障时,立刻切换到其他从节点或主节点。也可以通过 zk 等协调者解决。

建议:综上所述,使用 Redis 做读写分离有一定的成本,Redis 本身的性能非常高,如果已经解决了使用不当等问题,单机 Redis 还是无法满足,那么笔者建议调研 Redis Cluster 分布式解决方案,这样不止扩展读性能还可以扩展写性能,并且一致性和故障转移也可以得到保证。对于客户端的维护逻辑也相对容易。

主从配置不一致

这个总体来说是比较简单的,同时也是一个容易忽视的问题,对于有些配置可以不一样,例如从节点开启 AOF,主节点关闭 AOF。但是,关于内存方面的配置一定要相同,例如 maxmemoryhash-max-ziplist-entries 等参数,当从节点的内存小于主节点,如果复制的数据量超过了从节点的 maxmemory,他会根据淘汰策略(maxmemory-policy)进行内存溢出控制,此时从节点数据已经丢失,但主从复制流程依然正常进行,复制偏移量也正常,但主从数据已经不一致。

总结

本文主要总结了 Redis 复制的运维及优化,包括规避全量复制,规避复制风暴,读写分离的优化,主从配置不一致。使用 Redis 不仅仅是 set get,能够合理的运维也是非常重要的。

引用

《Redis 开发与运维》


Redis 复制运维及优化
http://thinkinjava.cn/2018/08/04/2018/2018-08-05-Redis 复制运维及优化/
作者
莫那·鲁道
发布于
2018年8月4日
许可协议