Redis 主从同步

288 阅读5分钟

概述

主从结构,一般有主节点 master 和从节点 slave ,一旦主节点挂掉,从节点会接管服务。所以,主从之间的同步,是我们关注的重点。

CAP 原理

  • C : Consistent, 一致性
  • A : Availability, 可用性
  • P : Partition tolerance, 分区容忍性

网络分区

image.png

  • 分布式系统节点都是分布在不同机器,通过网络进行交互而把他们相互隔离开,所以必然有网络断开的风险,我们称为「网络分区」。
  • 如果「网络分区」发生时,没法保证节点之间的数据同步,所以「一致性」无法得到保证。除非牺牲「可用性」,即暂停节点服务,不在提供修改的功能,直至网络恢复。
  • 所以,「网络分区」发生时,一致性和可用性两难全

最终一致性

  • 可用性:Redis 同步是异步同步的,只要主节点能正常工作,请求Redis就会立即返回,即可用性,不满足一致性。
  • 最终一致性:从节点会努力追赶主节点,最终从节点状态会和主节点状态保持一致。比如网络断开,主从节点数据不一致,一旦网络恢复,从节点会使用各种策略来追赶主节点,保证最终一致性。

从从同步

从从同步功能是 Redis 后续版本增加的功能,为了减轻主库的同步负担。后面为了描述上的方便,统一理解为主从同步。

image.png

增量同步

Redis 同步的是指令流,主节点会将那些对自己的状态产生 修改性影响的指令 记录在本地的内存 buffer 中,然后异步将 buffer 中的指令同步到从节点,从节点一边执行同步的指令流来达到和主节点一样的状态,一边向主节点反馈自己同步到哪里了 (偏移量)。

因为内存的 buffer 是有限的,所以 Redis 主库不能将所有的指令都记录在内存 buffer 中。Redis 的复制内存 buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容

image.png

如果因为网络状况不好,从节点在短时间内无法和主节点进行同步,那么当网络状况恢复时,Redis 的主节点中那些没有同步的指令在 buffer 中有可能已经被后续的指令覆盖掉了,从节点将无法直接通过指令流来进行同步,这个时候就需要用到更加复杂的同步机制 - 快照同步。

快照同步

快照同步是一个非常耗费资源的操作,它首先需要在主库上进行一次 bgsave 将当前内存的数据全部快照到磁盘文件中,然后再将快照文件的内容全部传送到从节点。从节点将快照文件接受完毕后,立即执行一次全量加载,加载之前先要将当前内存的数据清空。加载完毕后通知主节点继续进行增量同步。

image.png

在整个快照同步进行的过程中,主节点的复制 buffer 还在不停的往前移动,如果快照同步的时间过长或者复制 buffer 太小,都会导致同步期间的增量指令在复制 buffer 中被覆盖,这样就会导致快照同步完成后无法进行增量复制,然后会再次发起快照同步,如此极有可能会陷入快照同步的死循环。 所以务必配置一个合适的复制 buffer 大小参数,避免快照复制的死循环。

增加从节点 当从节点刚刚加入到集群时,它必须先要进行一次快照同步,同步完成后再继续进行增量同步。

无盘复制 主节点在进行快照同步时,会进行很重的文件 IO 操作,特别是对于非 SSD 磁盘存储时,快照会对系统的负载产生较大影响。特别是当系统正在进行 AOF 的 fsync 操作时如果发生快照,fsync 将会被推迟执行,这就会严重影响主节点的服务效率。

所以从 Redis 2.8.18 版开始支持无盘复制。所谓无盘复制是指主服务器直接通过套接字将快照内容发送到从节点,生成快照是一个遍历的过程,主节点会一边遍历内存,一边将序列化的内容发送到从节点,从节点还是跟之前一样,先将接收到的内容存储到磁盘文件中,再进行一次性加载。

Wait 指令

Redis 的复制是异步进行的,wait 指令可以让异步复制变身同步复制,确保系统的强一致性 (不严格)。wait 指令是 Redis3.0 版本以后才出现的。

> set key value
OK
> wait 1 0
(integer) 1

wait 提供两个参数,第一个参数是从库的数量 N,第二个参数是时间 t,以毫秒为单位。它表示等待 wait 指令之前的所有写操作同步到 N 个从库 (也就是确保 N 个从库的同步没有滞后),最多等待时间 t。如果时间 t=0,表示无限等待直到 N 个从库同步完成达成一致。

假设此时出现了网络分区,wait 指令第二个参数时间 t=0,主从同步无法继续进行,wait 指令会永远阻塞,Redis 服务器将丧失可用性。

小结

主从复制也不是必须的,如果Redis只是用来做缓存,无需主从复制,挂掉只需重启下。如果用到Redis持久化,就必须认真对待主从复制。

参考来源

《Redis深度历险 核心原理与应用实践》_钱文品