1、设置主服务器的地址和端口
首先是在从服务器设置需要同步的主服务器信息,包括机器IP, 端口。
主从复制的开启,完全是在从节点发起的。不需要我们在主节点做任何事情。
从节点开启主从复制,有3种方式
- 配置文件:在从服务器的配置文件中加入:slaveof 主机ip 主机port
- 启动命令: redis-server启动命令后加入 --slaveof 主机ip 主机port
- 客户端命令: redis服务启动后,在客户端执行slaveof IP port命令,此时该实例称为从节点.
2、建立socket套接字连接
在从节点执行完slave命令后,向主节点发起socket连接。
3、发送ping命令
发送ping命令进行首次请求,目的是:检查socket连接是否可用,以及主节点当前是否能够处理请求。
发送ping后可能会出现以下三种情况:
- 响应pong: 说明socket连接正常,且主节点当前可以处理请求,复制过程可以继续
- 超市,从节点未收到回复,则断开连接然后重试
- 返回pong以外的响应,比如正在处理超时的脚本等,说明主节点当前无法进行复制的过程,从节点断开连接并重试。
4、身份权限验证
- 如果从节点中设置了masterauth选项,则从节点需要向主节点进行身份验证;没有设置该选项,则不需要验证。
- 从节点进行身份验证是通过向主节点发送auth命令进行的,auth命令的参数即为配置文件中的masterauth的值。
- 如果主节点设置密码的状态,与从节点masterauth的状态一致(一致是指都存在,且密码相同,或者都不存在),则身份验证通过,复制过程继续;如果不一致,则从节点断开socket连接,并重连。
5、同步数据(pysnc)
同步就是将从节点的数据库状态更新成主节点当前的数据库状态。具体执行的方式是:从节点向主节点发送psync命令(Redis2.8以前是sync命令),开始同步。 数据同步阶段是主从复制最核心的阶段,根据主从节点当前状态的不同,可以分为全量复制和部分复制 。
6、命令持续复制
在数据同步之后,由于主节点不断的接受到写入命令,主从节点进入命令传播阶段,主节点将自己执行的写命令发送给从节点,从节点接收命令并执行,从而保证主从节点数据的一致性。
注意:
- 命令传播是异步的过程,即主节点发送写命令后并不会等待从节点的回复;因此实际上主从节点之间很难保持实时的一致性,延迟在所难免。数据不一致的程度,与主从节点之间的网络状况、主节点写命令的执行频率、以及主节点中的repl-disable-tcp-nodelay配置等有关。
主从持续复制阶段,从服务器会利用心跳检测机制定时的向主服务发送消息。
7、全量复制和部分复制
- 全量复制:用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作。
- 部分复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。需要注意的是,如果网络中断时间过长,导致主节点没有能够完整地保存中断期间执行的写命令,则无法进行部分复制,仍使用全量复制。
全量复制的过程:
1.从节点判断无法进行部分复制,向主节点发送全量复制的请求;或从节点发送部分复制的请求,但主节点判断无法进行部分复制;
2.主节点收到全量复制的命令后,执行bgsave,在后台生成RDB文件,并使用一个缓冲区(称为复制缓冲区)记录从现在开始执行的所有写命令。
3.主节点的bgsave执行完成后,将RDB文件发送给从节点;从节点首先清除自己的旧数据,然后载入接收的RDB文件,将数据库状态更新至主节点执行bgsave时的数据库状态。
4.主节点将缓冲区中的所有写命令发送给从节点,从节点执行这些写命令,将数据库状态更新至主节点的最新状态。
5.如果从节点开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主节点的最新状态。
全量复制流程图:
通过全量复制的过程可以看出,全量复制是非常重型的操作:
1.主节点通过bgsave命令fork子进程进行RDB持久化,该过程是非常消耗CPU、内存(页表复制)、硬盘IO的;
2.主节点通过网络将RDB文件发送给从节点,对主从节点的带宽都会带来很大的消耗。
3.从节点清空老数据、载入新RDB文件的过程是阻塞的,无法响应客户端的命令;如果从节点执行bgrewriteaof,也会带来额外的消耗。
部分复制
由于全量复制在主节点数据量较大时效率太低,因此提供部分复制的方式。
部分复制依赖于三个重要的概念:
1.复制偏移量
2.复制积压缓冲区
3.服务器运行ID(runid)
复制偏移量:
执行复制的双方,主从节点,分别会维护一个复制偏移量offset: 主节点每次向从节点同步了N字节数据后,将修改自己的复制偏移量offset+N 从节点每次从主节点同步了N字节数据后,将修改自己的复制偏移量offset+N。
offset用于判断主从节点的数据库状态是否一致: 如果二者offset相同,则一致; 如果offset不同,则不一致,此时可以根据两个offset找出从节点缺少的那部分数据。
复制积压缓冲区:
主节点内部维护了一个固定长度的、先进先出(FIFO)队列 作为复制积压缓冲区,其默认大小为1MB 在主节点进行命令传播时,不仅会将写命令同步到从节点,还会将写命令写入复制积压缓冲区。
由于复制积压缓冲区定长且是先进先出,所以它保存的是主节点最近执行的写命令;
当主从节点offset的差距过大超过缓冲区长度时,将无法执行部分复制,只能执行全量复制。
为了提高网络中断时部分复制执行的概率,可以根据需要增大复制积压缓冲区的大小(通过配置repl-backlog-size);例如如果网络中断的平均时间是60s,而主节点平均每秒产生的写命令(特定协议格式)所占的字节数为100KB,则复制积压缓冲区的平均需求为6MB,保险起见,可以设置为12MB,来保证绝大多数断线情况都可以使用部分复制。
从节点将offset发送给主节点后,主节点根据offset和缓冲区大小决定能否执行部分复制:
如果offset偏移量之后的数据,仍然都在复制积压缓冲区里,则执行部分复制;
如果offset偏移量之后的数据已不在复制积压缓冲区中(数据已被挤出),则执行全量复制。
服务器运行ID(runid):
1.每个Redis节点,都有其运行ID。
2.运行ID由节点在启动时自动生成。
3.主节点会将自己的运行ID发送给从节点,从节点会将主节点的运行ID存起来。
1.如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会继续尝试使用部分复制(到底能不能部分复制还要看offset和复制积压缓冲区的情况);
2.如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的Redis节点并不是当前的主节点,只能进行全量复制。
psync命令的大体流程
1.如果从节点之前没有复制过任何主节点,或者之前执行过slaveof no one命令,从节点就会向主节点发送psync命令,请求主节点进行数据的全量同步
2.如果前面从节点已经同步过部分数据,此时从节点就会发送psync {runid} {offset}命令给主节点,其中runid是上一次主节点的运行ID,offset是当前从节点的复制偏移量。
主节点收到psync命令后,会出现以下三种可能:
1.主节点返回 fullresync {runid} {offset}回复,表示主节点要求与从节点进行数据的完整全量复制,其中runid表示主节点的运行ID,offset表示当前主节点的复制偏移量
2.如果主服务器返回 +continue,表示主节点与从节点会进行部分数据的同步操作,将从服务器缺失的数据复制过来即可。
3.如果主服务器返回 -err,表示主服务器的Redis版本低于2.8,无法识别psync命令,此时从服务器会向主服务器发送sync命令,进行完整的数据全量复制
心跳检测机制的作用
1.检查主从服务器的网络连接状态 //主节点信息中可以看到所属的从节点的连接信息
state 表示从节点状态
offset 表示复制偏移量
lag 表示延迟值(几秒之前有过心跳检测机制)
2.辅助实现min-slaves选项
//如果将两个参数的注释取消,那么如果从服务器的数量少于3个,或者三个从服务器的延迟(lag)大于等于10秒时,主服务器都会拒绝执行写命令
min-slaves-to-write 3 //min-slaves-to-write 3
min-slaves-max-lag 10 //延迟值
3.检测命令丢失 //在从服务器的连接信息中可以看到复制偏移量,如果此时主服务器的复制偏移量与从服务器的复制偏移量不一致时,主服务器会补发缺失的数据。