Redis为了解决单点故障的问题,会将数据复制到多个从节点服务器中,通过复制,实现Redis的高可用。
1. 介绍
复制使得slave服务器能够精确复制master服务器的数据,每当slave和master连接断开时,slave会自动重连到master,并且无论这期间master做了什么操作,slave都将尝试让自身成为master的精确副本。
- 当一个master和slave连接正常时,master会将所有的修改命令发送给slave。
- 当master和slave之间因为某些原因断开连接后,slave会重新连接到master并尝试进行部分重同步。
- 当无法进行部分同步时,slave会请求全量同步。
Redis默认使用异步复制,即低延迟高性能,是绝大多Redis的自然复制模式。
配置Redis复制功能非常简单,只需加入下面内容到slave的配置文件即可,或在客户端中执行该命令。
1 | # 命令 主机ip地址 主机端口号 |
注:通常完全重同步需要在磁盘上创建RDB文件,然后slave获取此RDB文件进行复制。但如果磁盘性能很低会对master造成很大压力,所以可以通过socket直接发送给slave而不存储到磁盘中。
2. 工作原理
master使用复制ID和偏移量来标识当前复制的进度,复制ID用于标记数据集,偏移量用于标识此次复制中,master将多少字节已经发送给slave。而master自己则用于一块复制缓冲区域,用于缓存master产生的复制流。
当slave连接到master时,使用PSYNC命令发送旧的复制ID和已经处理的偏移量。如果复制ID与master匹配,且偏移量在复制积压缓冲区以内,则进行部分重同步;但否则的话,需要进行完全重同步。
复制ID标记数据集的历史记录,每次实例作为master重新启动或slave提升为master都会为其生成新的复制ID。
Redis实例拥有两个复制ID是因为到故障发生时,slave提升为master,slave需要记住过期的复制ID,该复制ID是之前的master,这样当其他slave与新master连接时,它们可以使用旧的复制ID尝试部分重同步。
2.1 部分重同步
主节点在复制过程中,会将命令传递给从节点的同时保存在一个叫做复制积压缓冲区backlog的区域内,当从节点重新连接到主节点,会发送自己的复制ID和偏移量,如果偏移量在主节点的缓冲区范围内,则可以进行部分重同步,只是少量的数据,而不需要全部的RDB文件。
复制积压缓冲区backlog是一个1M大小的循环队列,用于存储主节点传递的修改数据库的命令,也是部分重同步的重要部分,从节点通过偏移量和复制积压缓冲区就可以计算出与主节点的差异,如果在缓冲区中能找到则只需进行部分重同步,而无需完整的拷贝所有RDB文件
2.2 完全重同步
由于网络或其他原因,主从节点断线,当从节点重新连接到主节点时,主节点的复制积压缓冲区已经超过了从节点的偏移,此时无法进行部分重同步。
2.3 心跳检测
为了保持master与slave之间的连接,它们之间会不时的进行通信以保持对方的在线状态:
- master节点每隔10s(默认)向slave节点发送PING命令,判断从节点连接状态
- slave节点每秒发送
REPLCONF ACK <offset>
命令,给主节点报告自己当前复制偏移量
2.4 复制积压缓冲区backlog
复制积压缓冲区backlog是一个1M大小的循环队列,用于存储主节点传递的修改数据库的命令,也是部分重同步的重要部分,从节点通过偏移量和复制积压缓冲区就可以计算出与主节点的差异,如果在缓冲区中能找到则只需进行部分重同步,而无需完整的拷贝所有RDB文件
3. 实现
步骤1:设置主服务器的地址和端口
执行
SLAVEOF <master_ip> <master_port>
步骤2:建立socket连接
步骤3:发送PING命令
步骤4:身份验证
步骤5:发送端口信息
步骤6:同步
步骤7:命令传递
4. 源码剖析
- 复制周期性任务
1 | /* Replication cron function, called 1 time per second. */ |
- SYNC和PSYNC命令
1 | /** |