什么是主从复制
在分布式系统中,一台 Redis 服务器的数据自动复制(同步)到其它的 Redis 服务器上,称为主从复制,其中前者称为主节点(Master),后者称为从节点(Slave),主节点负责写入数据、从节点负责读取数据
一般来说,数据流动是单向的,只能从主节点流向从节点
一个主节点可以对应多个从节点,一个从节点只能对应一个主节点
主从复制的作用
读写分离
主节点提供写服务,从节点提供读服务,将读写分开,提高服务器的负载能力
负载均衡
根据需求的变化,可以改变从节点的数量,多个从节点分担数据读取任务,大大提高 Redis 服务器的并发量和数据吞吐量
故障恢复
当主节点出现故障时,可以由从节点提供服务,实现快速的故障恢复
数据备份
实现了数据的热备份,是持久化之外的另一种数据备份方式
高可用基石
主从复制是构建哨兵模式和集群的基础
主从复制的工作流程
建立连接
- 设置 master 的 IP 和端口,保存 master 信息
- 根据保存的信息创建连接 master 的 socket
- slave 周期性向 master 发送 ping 指令,确保连接正常
- slave 发送 auth password 指令进行权限验证(如果 master 设置密码)
- slave 向 master 发送自身的端口信息,master 保存该信息
从节点客户端指令连接
从节点客户端发送 slaveof 指令,连接指定的主节点
slaveof host port
从节点配置启动参数连接
从节点启动时,设置启动参数进行连接
redis-server --slaveof host port
从节点配置文件设置连接
在从节点的配置文件中,增加如下配置进行连接
slaveof host port
数据同步
服务器运行ID
每一台服务器每一次运行的身份识别码称为服务器运行ID(runid),由 40 位随机的 16 进制字符组成
复制积压缓冲区(replication backlog buffer)
复制积压缓冲区是一个先进先出的队列,每次 master 向 slave 传播命令时,命令也存储到复制积压缓冲区中,当 master 与某个 slave 的发生连接中断,再次连接后可从复制积压缓冲区中同步尚未复制的命令
复制积压缓冲区由两部分组成:复制偏移量(offset)和字节值(用于存储命令对应的编码字符)
当入队元素的数量大于队列长度时,最先入队的元素会被强制出队,所以当 master 和 slave 的连接中断时间过长,导致复制积压缓冲区丢失了一些数据时,只能进行全量复制
通常复制积压缓冲区简称为复制缓冲区
复制偏移量
参与复制的主从节点都会维护自身的复制偏移量
主节点在处理完写入命令后,会把命令的字节长度进行累加,存储在 info relication 中的 master_repl_offset 中
从节点每秒向主节点上报自身的复制偏移量,因此主节点也会保存从节点的复制偏移量
从节点在接收到主节点发送的命令后,对自身的偏移量进行相应的累加,存储在 info relication 中的 slave_repl_offset 指标中
通过对比主从节点的复制偏移量,来判断主从节点数据是否一致,以及根据复制偏移量的差异,来判断主从节点数据同步延迟大小
同步过程
全量复制
- slave 向 master 发送 psync2 指令请求同步数据,第一次发送 psync2 ? -1 ,因为第一次不知道 master 的 runid ,自己也没有 offset
- master 执行 bgsave 指令生成此时的数据快照 RDB 文件,同时 master 创建复制缓冲区(replication_buffer)存储此后的写命令
- master 通过 socket 将 RDB 文件以及 runid 和 offset 发送给 slave
- slave 保存 master 发来的 runid 和 offset ,并删除所有旧数据,执行 RDB 文件恢复过程
增量复制(部分复制)
- slave 向 master 发送 psync2 runid offset 命令
- master 接受命令,比对 runid 是否匹配,offset 是否在复制缓冲区中
- 如果 runid 与 offset 有一个不满足,执行全量复制(runid 不满足说明不是同一台服务器,offset 不满足说明复制缓冲区溢出,丢失了一些数据)
- 如果 runid 与 offset 满足,master 与 slave 的 offset 相同,则不做处理(说明数据已经同步)
- 如果 runid 与 offset 满足,master 与 slave 的 offset 不相同,master 将复制缓冲区中的数据,连同 offset 一并发给 slave
- slave 保存 master 的 offset ,并对收到的复制缓冲区的指令进行重写后执行
从 slave 发送 psync2 ? -1 指令开始,到 slave 收到 RDB 文件执行恢复数据任务,并保存传来的 runid 和 offset 的过程,称为全量复制
从 slave 发送 psync2 runid offset 指令开始,进行 runid 和 offset 的比对,并将复制缓冲区的数据从 master 发送到 slave ,slave 保存新的 offset 的过程,称为增量复制(部分复制)
命令传播
在数据同步完成后,如果主节点再次收到写命令,该命令会自动传到各个从节点,保证各个从节点的数据同步,这个过程称作命令传播
心跳机制
在命令传播阶段,master 和 slave 之间需要进行信息交换,使用心跳机制进行维护
master 心跳
- 指令:ping
- 周期:由配置文件中的 repl-ping-slave-period 决定,默认 10 秒
- 作用:判断 slave 是否在线
- 查询:info replication 中 slave 的 lag 项为 0 或 1 表示正常
slave 心跳
- 指令:replconf ack offset
- 周期:1 秒
- 作用:向 master 发送复制偏移量,获取新数据,并判断 master 是否在线
同步过程
与数据同步阶段的增量复制类似,但无需比对 runid ,slave 向 master 发送 replconf ack offset
- 如果 offset 不在 master 的复制缓冲区,执行全量复制
- 如果 offset 在 master 的复制缓冲区,且 master 与 slave 的 offset 相同,则不做处理
- 如果 offset 在 master 的复制缓冲区,但 master 与 slave 的 offset 不相同,master 将复制缓冲区中的数据,连同 offset 一并发给 slave
- slave 保存 master 的 offset ,并对收到的复制缓冲区的指令进行重写后执行
断开连接
从节点客户端发送指令,断开与主节点的连接
slaveof no one
授权访问
- master 配置文件设置密码
requirepass password
- master 客户端设置密码指令
config set requirepass password
- master 客户端获取密码指令
config get requirepass
- slave 客户端输入密码指令
auth password
- slave 配置文件设置登陆密码
masterauth password
- slave 启动参数设置登陆密码
redis-cli -a password
数据同步注意事项
- 当 master 数据量过大时,应该避开流量高峰期,以免造成 master 阻塞
- 复制缓冲区设置过小或全量复制时间过长时,可能会造成复制缓冲区数据溢出,会重新进行全量复制,导致死循环,可以在配置文件中设置复制缓冲区大小
repl-backlog-size 1mb
- 为了避免 slave 在主从复制期间响应请求导致数据不同步,设置该期间阻塞所有请求
slave-serve-stale-data yes
- 避免多个 slave 同时请求数据同步对带宽造成巨大冲击,适量错峰
- slave 过多时,可考虑调整拓扑结构为树形结构,中间层节点既是 master 又是 slave ,但会导致深层次的 slave 数据同步延迟较大