文章目录
- 同步机制
- 全量复制
- 增量复制
- 同步故障处理
- 拷贝超时
- 积压缓冲区拷贝溢出
- slave全量同步的响应问题
同步机制
Redis的主从同步机制可以确保redis的master和slave之间的数据同步。Redis在2.8及以上版本使用psync
命令完成主从数据同步。
同步方式包括:
- 全量复制
- 增量复制
全量复制
- slave第一次启动时,连接Master,发送PSYNC命令,格式为
psync {runId} {offset}
{runId} 为master的运行id;{offset}为slave自己的复制偏移量。
slave第一次连接master时,slave并不知道master的runId,也不知道自己偏移量,这时候slave会传一个问号和-1,告诉master节点是第一次同步。格式为psync ? -1每个Redis节点启动后,都会动态分配一个40位的十六进制字符串作为运行ID,即
{runId}
。运行ID的主要作用是用来唯一识别Redis节点。
参与复制的主从节点都会维护自身复制偏移量,即{offset}
。
- 当master接收到
psync ? -1
时,知道slave是要全量复制,就会将自己的runId和offset告知slave,回复命令fullresync {runId} {offset}
。同时,master会执行bgsave命令来生成rdb文件,期间的所有写命令将被写入缓冲区。
slave接受到master的回复命令后,会保存master的runId和offset,slave此时处于同步状态。
缓冲区本质上是先进先出(FIFO)的定长队列,能实现保存最近已复制数据的功能,用于部分复制和复制命令丢失的数据补救。
- master bgsave执行完毕,向slave发送rdb文件。rdb文件发送完毕后,开始向slave发送缓冲区中的写命令。
- slave收到rdb文件,丢弃所有旧数据,开始载入rdb文件。rdb文件同步结束之后,slave执行从master缓冲区发送过来的所有写命令。
- 此后 master 每执行一个写命令,就向slave发送相同的写命令。
增量复制
- 如果出现网络闪断或者命令丢失等异常情况时,当主从连接恢复后,由于从节点之前保存了自身已复制的偏移量和主节点的运行ID。因此会把它们当作psync参数发送给主节点,要求进行部分复制操作,格式为
psync {runId} {offset}
。 - 主节点接到psync命令后首先核对参数runId是否与自身一致,如果一致,说明之前复制的是当前主节点;之后根据参数offset在自身复制积压缓冲区查找,如果偏移量之后的数据存在缓冲区中,则对从节点发送
+continue
响应,表示可以进行部分复制;否则进行全量复制。 - 主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,保证主从复制进入正常状态。
同步故障处理
拷贝超时
对于数据量较大的主节点,比如生成的rdb文件超过6GB以上时要格外小心。传输文件这一步操作非常耗时,速度取决于主从节点之间网络带宽,通过细致分析full resync和masterslave这两行日志的时间差,可以算出rdb文件从创建到传输完毕消耗的总时间。如果总时间超过repl-timeout所配置的值(默认60秒),从节点将放弃接受rdb文件并清理已经下载的临时文件,导致全量复制失败。
针对数据量较大的节点,建议调大repl-timeout参数防止出现全量同步数据超时。
例如对于千兆网卡的机器,网卡带宽理论峰值大约每秒传输100MB,在不考虑其他进程消耗带宽的情况下,6GB的rdb文件至少需要60秒传输时间,默认配置下,极易出现主从数据同步超时。
积压缓冲区拷贝溢出
如果主节点创建和传输RDB的时间过长,对于高流量写入场景非常容易造成主节点复制客户端缓冲区溢出。默认配置为client-output-buffer-limit slave 256MB 64MB 60
,如果60秒内缓冲区消耗持续大于64MB或者直接超过256MB时,主节点将直接关闭复制客户端连接,造成全量同步失败。
因此,运维人员需要根据主节点数据量和写命令并发量调整client-output-buffer-limit slave配置,避免全量复制期间客户端缓冲区溢出。
slave全量同步的响应问题
slave节点接收完主节点传送来的全部数据后会清空自身旧数据,执行flash old data,然后加载rdb文件。对于较大的rdb文件,这一步操作依然比较耗时。
对于线上做读写分离的场景,从节点也负责响应读命令,如果slave节点正出于全量复制阶段,那么slave节点在响应读命令可能拿到过期或错误的数据。对于这种场景,redis复制提供了slave-server-stale-data yes参数(默认开启),如果开启则slave节点依然响应所有命令。对于无法容忍不一致的应用场景可以设置no来关闭命令执行,此时从节点除了info和slaveof命令之外所有的命令只返回sync with master in progress信息