redis主从复制中数据同步的原理
前言
redis主从复制解决的是redis主服务和从服务之间的数据同步的问题,主从服务是redis集群要解决的一个基础且重要的问题,学习一下还是很有必要的。
一个简单例子
下图是一个简单的主从服务,master有一个slave从服务,两台机器都会向外提供读,但写只能在主服务上,新写入redis的数据会同步给从服务,这个同步的过程叫做主从复制。
除此之外,一个主服务可以有多个从服务,而从服务只能对应一个主服务,另外从服务也可以有自己的从服务。如果复杂一点的话,主从服务的关系就是一棵树,主服务就是顶端的根节点,其他的都是从服务,数据从根节点“流入”,流向子孙结点。
相关命令
1)salveof
slaveof <host> <port>
salveof命令可以建立和解除主从关系,例如:slaveof 192.168.1.1 6379
可以将当前redis设置为192.168.1.1
上的从服务,当前的服务的数据会被清除,接下来就会同步主服务的数据过来了。slaveof no one
会解除主从关系,当前的服务重新成为主服务,数据不再同步。
2)info replication
info replication
可以查看主从复制相关信息。下面分别展示一下主服务和从服务的相关信息。
主服务上执行:
role:master
:表明这是一个主节点
connected_slaves:1
:当前有一个从节点
slave0:ip=172.18.0.3,port=6379,state=online,offset=131,lag=0
: 显示了这个这个从节点的信息,如果有多个从服务,还会有salve1…等等的心思。很明显,这里显示了从节点的ip和端口,state表示从节点的当前的状态。offset用于数据同步,lag表示从节点“落后”了多少数据,lag=0表示主从结点的数据是一致的。
master_replid:372e55af72a6c4e4ed5b804fb0c0c06c3ab61258
:master的id值,用于唯一标记一个结点,从节点同步时会记住这个id,同步时会校验主结点的id是否匹配。
master_repl_offset:131
:这是一个偏移量,主节点会将新写的数据缓存在一个队里里面,从节点同步时会保存当前同步的偏移量,从节点同步主节点数据时,会将主机点的id和上次保存的偏移量发送给主节点,主节点收到同步请求后,如果id和自己的id相同而且发送来的偏移量比自己记录的偏移小,说明新写的数据没同步,遍将N字节的数据和偏移量+N一并发送给从节点。从节点收到数据后,记住偏移量用于下一次同步使用。
在从节点上执行:
role:slave
:表明此节点是从服务
master_host:master
:主节点ip,由于我使用的是docker,在docker实例中,我指定了主节点的hostname为master,而docker的user bridge网络类型为连在这个网络下的主从结点提供了自动DNS服务,所以我配置的master最终会被解析成主节点的ip
master_port:6379
:主节点端口
master_replid:372e55af72a6c4e4ed5b804fb0c0c06c3ab61258
:主节点的id,注意看主节点的是一致的。
master_repl_offset:3883
:偏移量,用于同步数据,同上。
同步原理
Redis在2.8之前使用SYNC命令同步,之后便用PSYNC命令替代了SYNC命令。下面重点介绍PSYNC命令。
全量同步和部分同步
PSYNC同步数据有两个模式:全量和部分,从节点发送PSYNC <id> <offset>
命令请求个主节点进行数据同步,主节点根据情况选择同步的方式。
- 全量同步用于从节点第一次同步主节点数据。主节点会fork出一个进程进行RDB备份,主节点会将RDB文件和缓冲区的数据发送给从节点完成数据同步。
- 部分同步用于第一次同步之后的数据同步,这时候只需要同步缓冲区里面新增的写命令即可。
几个概念
在解释同步的过程之前先澄清几个概念。
1)复制缓冲区
主从结点是通过生成RDB快照文件进行数据同步的。假设现在数据同步,主节点开始生成RDB文件。由于同Fork进程的方式,主进程还在处理客户端的写命令,那新写入redis的数据如何同步?(fork相关有个重要的概念:copy on write,fork出的子进程备份的RDB文件是旧的,在fork后写入主进程的数据子进程不能获取到,所以RDB文件里面只有旧数据)Redis使用了一个队列缓冲区暂时存储新的写命令,待从节点恢复完RDB文件,再把缓冲区的数据发送给从节点,一次来达到数据的一致性。
2)结点ID
每个redis实例运行都会生成自己的id,这个id用于数据同步和主从关系的验证等等。上面介绍info replication命令时,输出的信息中就包含主从结点的id和偏移量。
3)复制偏移量
完成第一次数据同步之后,新的写命令都将入到固定大小的缓冲区队列中,从节点同步是只需要同步缓冲区的数据就可以了。那么问题了,从节点应该同步缓冲区中那一部分的数据呢?偏移量便是用来解决这个问题的。假设主从结点完成一次同步,那么他们的保存的偏移都是相等的。这时候主节点又写入了N字节数据,主节点偏移量+N。这时候从节点发送PSYNC请求同步,主节点比较发送来的偏移量offset
和自己当前的偏移量offset+N
,发现有N字节的新数据,于是将N字节的数据发送给从节点。从节点的偏移量变成了offset+N
,自此,数据又达成一致。
但是有一些情况,需要重新进行RDB快照同步的。例如,从节点由于网络抖动等原因太久没和主节点同步,或者主节点短时间有大量的写入,超过了缓冲区大小。主节点一看offset+N
-offset
>缓冲区大小
,这时候就需要进行RDB快照同步了。
4)PSYNC命令
主从结点通过PSYNC命令进行数据同步。
从节点发送PSYNC命令:
- 第一次同步发送
PSYNC ? -1
到主节点请求数据同步。 - 第一次同步后发送
PSYNC id offset
到主节点请求数据同步,主节点根据offset值进行部分同步或者全量同步。
主节点处理PSYNC命令:
- 主节点返回
FULLRESYNC <id> <offset>
进行全量同步。 - 主节点返回
+CONTINUE
进行部分同步 - 主节点返回
-ERR
,表示主服务redis版本低于2.8,不能PSYNC命令,从服务将使用SYNC命令进行同步。
使用PSYNC同步过程: