Redis - 主从同步
Redis 主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其它从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行读写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整对消息发布记录。同步对读取操作对可扩展性和数据冗余很有帮助
有了主从,当 master 挂掉的时候,让从库过来接管,服务就可以继续,否则 master 需要经过数据恢复和重启的过程,这种可能会拖很长的时间,影响线上业务的持续服务。
在了解 Redis 的主从复制之前,让我能先来理解一下现代分布式系统的理论基石 ——-- CAP 理论。
CAP理论
它是分布式存储的理论基石。自打 CAP 的论文发表之后,分布式存储中间件犹如雨后春笋般一个一个涌现出来。
- C - Consistent 一致性
- A - Availability 可用性
- P - Partition tolerance 分区容错性
分布式系统的节点往往都是分步在不同的机器上进行网络隔离开的,这意味着必然会有网络断开的分险,这个网络断开的场景的专业词汇叫【网络分区】
在网络分区发生时,两个分布式节点之间无法进行通信,我们对一个节点进行对修改操作将我要发同步到另一个节点,所以数据到【一致性】将无法满足,因为两个分布式节点到数据不再保持一致。除非我们牺牲可用性,也就是暂停分布式节点服务,在网络分区发生时,不再提供修改数据的功能,直到网络状况完全恢复正常再继续对外提供服务。
一句话概括 CAP 原理就是——网络分区发生时,一致性和可用性两难全。
最终一致
Redis 的主从数据是异步同步的,所以分布式的 Redis 系统并不满足 【一致性】要求。当客户端在 Redis 的主节点修改了数据后,立即返回,即使在主从网络断开的情况下,主节点依旧可以正常对外提供修改服务,所以 Redis 满足 【可用性】
Redis 保证 【最终一致性】,从节点会努力追赶主节点,最终从节点的状态会和主节点的状态将保持一致。如果网络断开了,总从节点的数据将会出现大量不一致,一旦网络恢复,从节点会采用多种策略努力追赶上落后的数据,继续尽力保持和主节点一致。
主从同步
Redis 同步支持主从同步和从从同步,从从同步功能是 Redis 后续版本增加的功能,为了减轻主库的同步负担。后面为了描述上的方便,统一理解为主从同步。
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
增量同步
Redis 同步的是指令流,主节点会将那些对自己对状态产生修改影响对指令记录在本地的内存 buffer 中,然后异步将 buffer 中指令同步到从节点,从节点一边执行同步的指令流来达到和主节点一样的状态,一边向主节点反馈自己同步到哪里来(偏移量)。
因为内存的 buffer 是有限的,所以 Redis 主库不能将所有的指令都记录在 buffer 中。Redis 的复制内存 buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容。
如果因为网络状况不好,从节点在短时间内无法和主节点进行同步,那么当网络状况恢复时,Redis 的主节点中那些没有同步的指令在 buffer 中有可能已经被后续的指令覆盖掉了,从节点将无法直接通过指令流来进行同步,这个时候就需要用到更加复杂的同步机制 —— 全量同步。
全量同步
- 从服务器连接主服务器,发送sync命令
- 主服务器收到sync命令后,开始执行 bgsave 命令生成RDB文件并使用缓存区记录此后执行所有写命令
- 主服务器bgsave执行完后,向所有服务器发送快照文件,并在发送期间继续记录被执行的写命令
- 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令
在整个全量同步进行的过程中,主节点的复制 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 的集群模式,这几种集群模式都依赖于本节所讲的主从复制。
不过复制功能也不是必须的,如果你将 Redis 只用来做缓存,跟 memcache 一样来对待,也就无需要从库做备份,挂掉了重新启动一下就行。但是只要你使用了 Redis 的持久化功能,就必须认真对待主从复制,它是系统数据安全的基础保障。