基于redis的复制特性,使用和配置主从复制变得简单,能使得从redis服务器(slave) 能精确复制主redis服务器的内容,每当slave和master之间的连接断开,slave都会自动重连到master,并且无论这期间master发生了什么,lasve都将尝试让自身成为master的精确副本
在redis中用户可以通过执行slaveof命令或者让设置slaveof选项让一个服务器去同步另一个服务器
2.8版本之前的reidis复制功能
redis的复制功能分为同步(sync)和命令传播(command propagate)两个操作:
- 同步操作用于将从服务器的数据库状态更新值主服务器所处的数据路状态
- 命令传播用于在主服务器的数据库状态被修改,导致主从不一致时,让主从重新回到一致状态
同步
,从服务器首先需要执行的就是同步操作:
- 从服务器向主服务器发送sync命令
- 收到sync命令的主服务器执行bgsave命令,在后台生成一个rdb文件,并且使用缓冲区记录bgsave期间所有写命令
- 主服务器bgsave命令执行完毕,主服务器将rdb文件发送给从服务器,从服务器接受rdb文件将从服务器数据库更新至主服务器执行bgsave命令时的数据库状态
- 主服务器将缓冲区中所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器当前状态
命令传播
在sync执行完毕后主从达到了短暂一致,每当主服务器执行新的写操作,那么主从将不再一致;为了让主从重新回归一致,主服务器就必须在执行写命令之后,将写命令同步传播给从服务器,保证主从再次一致
缺陷
- 同步缺陷:
- 当redis主从复制中因为网络关系中断同步,当网络恢复从服务器自动重连主服务器继续复制
- 主从断线重同步是从服务器再次向主服务器发送sync命令,从头开始重新同步
- 从头开始重新同步导致重复同步,效率很低!
- 命令传播缺陷:
- 当命令传播是主从网络异常,命令传播丢失,主从服务器无法保障命令丢失情况下的一致性
2.8版本之后的redis复制功能
同步缺陷解决:psync
psync命令具有完整重同步和部分重同步两种模式
- 完整重同步
- 用于处理初次复制情况,完整重同步与sync命令执行重同步步骤是基本一致的
- 部分重同步
- 用于处理断线重启复制情况,当从服务器在断线后重新连接主服务器时,如果条件允许
- 主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器
- 从服务器只要接受并执行这些命令,就可以将数据库更新至主服务器当前状态
- 解决了2.8版本之前的sync断线重连同步低效问题
psync部分重同步实现
psync的重同步功能由三个部分构成:
- 主服务器的复制偏移量和从服务器的复制偏移量
- 执行复制的双方都会维护一个复制偏移量
- 主服务器每次向从服务器传播n个字节数据,主服务器的复制偏移量+n
- 从服务器每次接收主服务器传播的n个字节数据,从服务器的复制偏移量+n
- 通过比较主从服务器的复制偏移量,就可以知道主从是否一致
- 主服务器的复制积压缓冲区(replication backlog)
- 主服务器维护的一个固定长度先进先出的队列,默认大小1mb
- 当主服务器进行命令传播时,不仅会将写命令发送给所有从服务器,还会将写命令入队到复制积压缓冲区
-
复制积压缓冲区会为队列中命令记录对应的复制偏移量
- 复制积压缓冲区可以调整:seconds*write_size_pre_second
- 设置合理大小的复制积压缓冲区可以提高复制效率,减少完整重同步的可能
- 可以通过修改repl-backlog-size选项来设置
- 当从服务器重新上线,从服务器会通过psync命令将自己的复制偏移量offset发送给主服务器
- 主服务器会根据这个复制偏移量来决定对从服务器执行何种同步操作
- 如果offest之后的数据在复制积压缓冲区中,主服务器对从服务器执行部分重同步操作
- 如果offset之后数据不在复制积压缓冲区中,主服务器对从服务器执行完整重同步操作
- 服务器的运行ID(run-id)
- 每个redis服务器不论主服务器还是从服务器都会有自己的运行id
- 运行id在服务器启动时自动生成,由40个随机字符组成
- 当从服务器首次复制时,主服务器会将自己的运行id传送给从服务器,从服务器会将这个主服务器运行id保存
- 当从服务器断线重连时,从服务器会向当前连接的主服务器发送自己保存的主服务器运行id
- 运行id相同,说明主服务器就是之前的服务器,可以尝试部分重同步
- 运行id不同,说明服务器不是之前的服务器,执行完整重同步
命令传播缺陷解决
根据replconf ack和复制积压缓冲区解决命令传播丢失问题
心跳检测机制:
在命令传播阶段,从服务器默认会以每秒一次的频率向主服务器发送命令:
- replconf ack <replication_offset>;心跳检测用于:
- 检测主从服务器网络连接状态
- 主服务器超过一秒未收到从服务器ack命令,那么说明主从网络有问题
- 辅助实现min-slaves
- min-slaves-to-write
- min-slaves-max-lag
- 当从服务器数量小于min-slaves-to-write或者所有从服务器延迟都大于min-slaves-max-lag主服务器拒绝执行写命令
- 检测命令丢失
- 在命令传播阶段从服务器会向主服务器发送replconf ack命令
- ack命令会将从服务器的复制偏移量发送到主服务器
- 主服务器会比较主从的复制偏移量
- 如果主复制偏移量>从复制偏移量,那么说明命令传播丢失,从复制积压缓冲区开始做同步
总结
- redis的复制时异步的,特点是低延迟和高性能
- redis的复制推荐使用2.8版本之后的功能
- redis复制在master侧是非阻塞的,可以一边同步一边处理客户端命令
- redis复制在slave侧也是非阻塞的,可以处理客户端的命令
- 复制积压缓冲区大小对于断线重连复制的效率很重要,合理选择大小(seconds*write_size_pre_second),可以尽可能的减少全量同步次数
- 命令传播不丢失是基于心跳检测的replconf ack offset命令来保障主从之间命令传播一致