主从复制作用:
- 读写分离
- 负载均衡
- 容灾恢复
- 数据冗余,实现数据热备份。
- 高可用与高并发基石,基于主从复制,构建哨兵模式与集群。
主从复制过程
主从复制分为三个阶段:
- 建立连接阶段
- 数据同步阶段
- 命令传播阶段
建立连接阶段
建立连接阶段slave工作流程:
步骤1:发送连接请求。
步骤2:设置master的地址和端口,保存master信息。
步骤3:建立socket连接。
步骤4:发送Ping命令(定时)。
步骤5:进行身份验证。
步骤6:发送slave端口信息。
建立主从连接三种方式
方式一:客户端发送命令
slaveof masterip masterport
方式二:启动服务器参数
redis-server --slaveof masterip masterport
方式三:服务器配置
slaveof masterip masterport
数据同步阶段
数据同步阶段分为全量复制阶段和增量复制阶段。
增量复制的三个核心要素:
- 服务器运行id(run id)
- 主服务器的复制积压缓冲区(简称缓冲区)
- 主从服务器的复制偏移量 offset
基本思路
master在全量复制阶段使用RDB持久化将数据快照发送给slave。在slave使用.rdb文件恢复期间,master接收到的指令存到命令缓冲区中。待slave恢复完毕后,将暂存区中信息发送到slave中。
数据同步阶段工作流程
步骤1:请求同步数据
步骤2:创建RDB同步数据
步骤3:恢复RDB同步数据
步骤4:请求部分同步数据
步骤5:恢复部分同步数据
run id
服务器运行id是每台服务器每次运行的身份识别码,一台服务器多次运行会生成多个run id。
作用:run id在服务器间传输,识别身份。在增量服务时,slave传递请求时会携带run id进行身份识别;若run id不一致时,会直接重新进行全量复制。
实现方式:run id在每台服务器启动时自动生成,master首次连接slave时,会将自己的run id发送给slave,slave保存run id。
复制积压缓冲区
复制挤压缓冲区时一个队列(FIFO),用于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,存储在缓冲区中。
offset偏移量:
master记录已发送信息对应的offset(多个);
slave记录已接收的offset(一个);
通过offset来区分不同的slave数据传播的差异。
全量复制与增量复制
全量复制
slave发送指令 psync2
master执行bgsave
master在第一个slave连接时,创建命令缓冲区
master生成RDB文件,通过socket发送给slave
slave接受RDB文件,清空数据,执行RDB文件恢复过程
增量复制
slave发送命令告知RDB恢复已经完成
master发送复制缓冲区信息
接受信息,执行bgrewriteaof,恢复数据
在增量复制阶段,master识别slave是依靠run id和offset的。
检验run id是否为自己的run id,然后校验 offset 是否在复制缓冲区中。
若offset在复制缓冲区中存在,则与master中的offset数值进行对比。
若run id或offset有校验不通过情况,slave重新执行全量复制。
若offset数值不一致,进入命令传播阶段。
数据传播阶段
当master数据库状态被修改后,导致主从服务器数据库状态不一致,此时需要让主从数据同步到一致的状态,同步的动作称为命令传播。
master将收到的数据变更命令发送给slave,slave接受命令后执行命令。
心跳机制
进入命令传播阶段,master与slave间需要进行信息交换,使用心跳机制维护,实现双方保持在线。
master心跳
指令:PING
周期:由repl-ping-slave-period决定,默认10s
作用:判断slave是否在线
查询:INFO replication 获取slave最后一次连接时间间隔,lag维持在0或1视为正常。
slave心跳
指令: REPLCONF ACK{offset}
周期:1秒
作用1 汇报slave自己的offset,获取最新的数据变更指令
作用2 判断master是否在线
主从复制常见问题
在使用主从复制时,应注意全量复制次数,全量复制使用RDB持久化,无论是master还是slave,多次全量复制都会大大消耗性能。
多次全量复制
1.master数据量逐渐增大,一旦master重启,runid将发生变化,会导致slave的全量复制操作。
解决方案:
- master内部创建master_replid变量,使用runid相同的策略生成,并发送给所有的slave。
- 在master关闭时执行命令shutdown save,进行RDB持久化,将runid与offset保存在RDB文件中。
- master重启后加载.rdb文件,恢复数据。重启后将.rdb文件中的repl-id与repl-offset加载到内存中。
作用:本机保存上次runid,重启后恢复该值,使所有的slave认为还是之前的master。
2.网络不佳,出现网络中断,slave不提供服务。
问题原因:由于复制缓冲区太小,断网后slave的offset月结,触发全量复制。
解决方案:修改复制缓冲区大小,repl-backlog-size。
测算从master到slave的重连平均时长second。
获取master平均每秒产生写命令数据总量write_size_per_second。
最优复制缓冲区空间 = 2 * second * write_size_per_second。
3.多次网络中断,master与slave连接断开。
问题原因:
master发送ping指令频度较低
master设定超时时间较短
ping指令在网络中存在丢包
解决方案:提高ping指令发送的频度。
repl-ping-slave-period 设置频度
4.数据不一致问题
问题现象:
多个slave获取相同数据不同步。
问题原因:
网络信息不同步,数据发送有延迟。
解决方案:
优化主从间网络环境,通常放置在同一个机房部署。
监控主从节点延迟(根据offset)判断,如果slave延迟过大,暂时屏蔽程序对该slave的访问
salve-serve-stale-data yes|no