为什么需要主从同步
生产环境中,如果redis只有一台机器是一件很危险的事情,如果出现机器宕机服务将处于不可用状态,此时需要对挂掉的节点进行重启和等待数据恢复后,服务方可继续对外使用,
如果有了主从以后,当主节点挂掉后,运维将从节点升级为主节点即可继续对外提供服务,可以省去中间的恢复原本主节点的时间,提高了可用性。
CAP 与 最终一致
CAP是分布式系统的理论基石,C 代表 一致性 (Consistent)、A 代表 可用性 (Availability) 、P (Partition tolerance) 代表 分区容忍性,
分布式系统一般都是在不同的机器上通过网络进行交互,但是网络一般都会有断开的风险,网络断开的场景一般称之为 网络分区 。
当网络分区发生时,两个分布式节点无法通过网络进行通信,对其中一个节点的修改操作无法同步到另一个节点中,因为两个节点中的数据不同,所以此时数据的 一致性 无法满足,
如果要满足一致性,那么这个时候就需要暂停分布式节点对外的服务,等待网络分区恢复,两个节点正常通信数据保持一致后,再对外提供服务,但此时的 可用性 将无法满足,
因此CAP的概述其实就是,网络分区发生时,一致性和可用性两难全。
Redis的最终一致性
redis的主从节点之间,数据是异步同步的,所以分布式的redis系统并不符合一致性的要求,即使主从断开连接,主节点依旧可以正常对外提供服务,所以redis符合的是可用性。
redis保证最终一致性,从节点会努力追赶主节点的数据,最终在某个时间数据将和主节点相同,如果发生网络分区,主从数据不一致,当网络恢复后,从节点将会通过多种同步策略保证与主节点数据一致。
同步方式
redis持久化有两种方式,一种是全量持久化,一种是增量持久化,节点之间同步也是两种,即全量同步与增量同步。
Redis从节点与主节点建立通信进行数据同步,这种模式称之为主从同步,不过为了减轻主节点一对过多的节点,可能会产生很大的压力,redis也支持从从同步,以此减轻主节点的压力。
增量同步
与增量备份类似,增量同步也是将对redis具有修改性的指令进行存储,只是备份存到了AOF日志中,而同步是存在本地的内存buffer(一个定长的环形数组,如下图)中,然后异步将buffer中的指令同步到从节点,
从节点一边执行同步的指令流来达到和主节点一样的状态,一边向主节点反馈自己同步到了什么位置(偏移量),
buffer的内存空间是有限的,无限的指令不会一直存在有限的buffer中,如果buffer数组满了,将会从头开始覆盖前面的内容,
如果因为网络状况不好,从节点短期内无法和主节点进行同步,当网络状况恢复时,buffer中没有被同步的指令很有可能已经被后续的指令覆盖了,从节点无法通过指令流来进行同步追赶保证一致,这时候就需要快照(全量)同步来保证一致性。
快照同步
快照同步与快照备份类似,首先在主节点上进行一次bgsave,将当前内存数据存到全部存到磁盘文件上,然后将文件传送给从节点,
从节点接收完毕快照文件后,先将当前内存中的数据清空,然后加载快照文件中的数据,加载完毕以后通知主节点继续进行增量同步。
问题
在快照同步的过程中,主节点的指令buffer还在不停的增加,如果同步的时间过长或者buffer过小,会导致buffer中的指令被新的指令覆盖,
这样快照同步完成后依然无法使用增量同步保证一致,此时将继续发起快照同步,这样会出现死循环的情况,因此需要配置一个合适的buffer大小,保证不会出现指令覆盖,防止出现死循环。
无盘复制同步
主节点进行快照同步时,将文件保存到本地磁盘是一个很耗时的文件IO操作,如果是非SSD磁盘存储,快照同步对系统的负载会造成较大的影响。
如果系统正在进行AOF的fsync操作时,快照同步会导致fsync推迟执行,影响主节点的服务效率。
从redis2.8.18开始,redis支持无盘复制,快照同步将不会进行磁盘操作,生产快照是一个遍历内存的过程,主节点一边遍历一边将序列化的内容发送给从节点,从节点将接收的内容存在磁盘文件中,最后进行一次性加载。
新增的从节点如何同步
当有新的从节点加入时,将进行一次快照同步,后续则是增量同步。
wait指令同步
redis的数据同步是异步进行的,在3.0版本后提供了一个wait指令,该指令将异步复制变成同步复制,保证请求返回后,主从节点都含有该数据。
wait指令提供两个参数,第一个是从节点的数量N,第二个是时间t(单位是毫秒),前者代表wait指令之前的写操作同步到N个节点上(保证N个节点没有滞后),后者是等待时间(最多等多久后返回),
如果时间t=0,表示无限等待直到N个节点同步完成,如果t=0,此时发生网络分区,主从同步无法进行,wait指令会一直阻塞,redis主节点无法对其他客户端进行响应,此时redis丧失可用性。