首页 / REDIS / Redis主从复制过程详解
Redis主从复制过程详解
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Redis主从复制过程详解,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含12328字,纯文字阅读大概需要18分钟。
内容图文
![Redis主从复制过程详解](/upload/InfoBanner/zyjiaocheng/873/7c4f081d752d41eb96a85f346f89f622.jpg)
文章目录
引言
Redis的复制功能分为同步
和传播
两个过程:
同步
:将从服务器的数据库状态更新至主服务器当前所处的状态;传播
:在主服务器的数据库状态被修改导致主从服务器数据库状态出现不一致时(如,主服务器执行写命令后),让主从服务器的数据库重新达到一致状态;
1. 相关命令
slaveof host port
- 设置当前服务器去复制运行在
host:port
的服务器,当前服务器被称为从服务器,被复制的服务器称为主服务器;
slaveof no one
- 取消复制其他服务器
info replication
- 查看当前服务器的复制信息
2. 同步
2.1 两种需要同步的情况
在两种情况下需要执行数据库同步:初次复制
和断线后复制
;
- 初次复制:
- 从服务器以前没有复制过任何主服务器(即使以前复制过主服务器,只要执行过
slaveof no one
也认为没有复制过任何主服务器,即当前服务器状态是master
) - 或者,从服务器当前要复制的主服务器和上次复制的主服务器不同(即,需要重新执行同步)
- 断线后重复制:
- 处于命令传播阶段的主从服务器因为网络原因中断了复制,但从服务器通过自动重连重新连接上了主服务器,并继续复制主服务器;
2.2 两种同步方法
Redis2.8以前的版本,使用SYNC
命令,在两种情况下都实行完整同步,Redis2.8版本开始使用PSYNC
命令代替SYNC
命令,支持两种同步方式:完整重同步和部分重同步
- 完整重同步:将主服务器的数据库状态在后台生成RDB文件,发送给从服务器,从服务器加载RDB文件达到数据库状态一致。步骤:
- 从服务器向主服务器发送同步命令(
SYNC
或PSYNC
); - 主服务器收到同步命令后,执行
BGSAVE
命令,在后台生成RDB文件,同时使用一个缓冲区记录生成RDB文件期间,主服务器执行的新的写命令; - 主服务器的
BGSAVE
命令执行完毕后,主服务器将生成的RDB文件发送给从服务器; - 从服务器接收并载入RDB文件,将自己的数据库状态更新至主服务器执行
BGSAVE
命令时的状态; - 主服务器将记录在缓冲区里面的所有新产生的写命令发送给从服务器;
- 从服务器执行这些写命令,将自己的数据库状态更新至主服务器当前所处的状态;
- 主从服务器数据库状态达到一致,之后主服务器再有写命令,通过命令传播发送给从服务器,保证主从服务器的数据库状态一致;
- 部分重同步:主服务器将断线期间的命令发送给从服务器,从服务器接收并执行这些命令完成数据库状态一致。
- 当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器可以将从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前的状态;
- 部分重同步依赖服务器运行ID、复制积压缓存区、复制偏移量来实现断线期间缺失命令的补发;
2.3 SYNC
和PSYNC
命令
SYNC
SYNC
命令是Redis2.8以前使用的同步命令;在初次复制和断线后重复制时都使用完整同步;- 完整同步是一个非常耗费资源的操作:
- 主服务器需要执行
BGSAVE
命令来生成RDB文件,这个生成操作会耗费主服务器大量的CPU、内存和磁盘I/O资源; - 主服务器需要将生成的RDB文件发送给从服务器,这个发送操作会耗费主从服务器大量的网络资源,并对主服务器响应命令请求的时间产生影响;
- 从服务器接收到RDB文件后需要载入,在载入期间,从服务器会因为阻塞而没有办法处理命令请求(载入RDB文件时,会阻塞客户端请求操作,在服务器启动载入RDB文件时也是如此);
- 在从服务器断线后重连时,可能只是缺失了少部分命令,在这种情况下,为了让从服务器补足一小部分缺失的数据,却要让主从服务器重新执行一次完整同步,这种做法是非常低效的
PSYNC
- 为了解决旧版本复制功能在处理断线重复制情况时的低效问题,Redis从2.8版本开始,使用
PSYNC
命令代替SYNC
命令来执行复制时的同步操作; PSYNC
支持完整同步和部分同步,在初次复制时,执行完整同步,在断线重复制时,根据情况执行完整重同步(full resynchronization)或部分重同步(partial resynchronization);
2.4 部分重同步的实现
部分重同步功能由以下三个部分构成:
- 服务器的运行ID;
- 复制积压缓冲区;
- 复制偏移量;
服务器运行ID
- 每个Redis服务器,不论主服务器还是从服务器,都会有自己的运行ID,由40个随机的十六进制字符组成;
- 当从服务器对主服务器进行初次复制时,主服务器会将自己的运行ID传送给从服务器,而从服务器会将这个运行ID保存起来;
- 当从服务器断线重新连上一个主服务器时,从服务器将向当前连接的主服务器发送之前保存的运行ID;
主服务器接收到运行ID后,执行判断:
- 如果从服务器保存的运行ID和当前连接的主服务器的运行ID相同,那么说明从服务器断线之前复制的就是当前连接的这个主服务器,主服务器可以继续尝试执行部分重同步操作(只是可以尝试执行,并不一定能够执行部分重同步,还跟偏移量是否在复制积压缓冲区有关);
- 相反的,如果从服务器保存的运行ID和当前连接的主服务器的运行ID并不相同,那么说明从服务器断线之前复制的主服务器并不是当前连接的主服务器,主服务器将对从服务器执行完整重同步操作;
复制积压缓冲区
复制积压缓存区是由主服务器维护的一个固定长度的先进先出的队列,默认大小是1MB;
- 固定长度先进先出队列的长度是一定的,当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新元素会被放入队列;
- 缓冲区大小默认是1MB,缓冲区越小,断线重连后
offset
不在缓冲区的几率越大,越可能需要执行完整重同步,可以通过配置参数适当调高缓冲区大小:
# repl-backlog-size 1mb
- 当主服务器进行命令传播时,它不仅会将写命令发送给所有从服务器,还会将写命令入队到复制积压缓冲区;
- 当从服务器重新连接上主服务器时,从服务器会通过
PSYNC
命令将自己的复制偏移量offset
发送给主服务器,主服务器会根据这个复制偏移量决定对从服务器执行何种同步操作:
- 如果
offset
偏移量之后的数据仍然存在于复制积压缓冲区中,那么主服务器对从服务器执行部分重同步; - 相反,如果
offset
偏移量之后的数据已经不存在于复制积压缓冲区,那么主服务器将对从服务器执行完整重同步;
复制偏移量
执行复制的主服务器和从服务器都会分别维护一个复制偏移量
- 主服务器每次向从服务器传播N个字节的数据时,就会将自己的偏移量的值加上N;
- 从服务器每次收到主服务器传播来的N个字节的数据时,就会将自己的复制偏移量的值加上N;
- 偏移量记录的是主从之间复制的命令的字节数;
通过对比主从服务器的复制偏移量,程序可以很容易地知道主从服务器是否处于一致状态;
2.5 PSYNC命令的实现
PSYNC命令的格式
PSYNC <runid> <offset>
runid
是主服务器的运行ID;offset
是从服务器的复制偏移量;
从服务器发送的PSYNC
命令,分为两种情况:
- 初次复制时:从服务器以前没有复制过任何主服务器,或者之前执行过
slaveof no one
,从服务器知道要开始一次新的复制,这时需要执行完整重同步,所以向服务器发送PSYNC ? -1
命令
runid
:是?
号,表示需要主服务器发送offset
:复制偏移量-1
;
- 断线重复制时:如果从服务器已经复制过某个主服务器(可能不是当前的主服务器),那么从服务器开始一次新的复制时,将向主服务器发送
PSYNC <runid> <offset>
命令
runid
:是上一次复制的主服务器的运行ID;offset
:是从服务器当前的复制偏移量;
主服务器接收到PSYNC
命令后,三种回复:
- 如果
runid
是当前主服务器的运行ID,并且offset
偏移之后的数据还在复制积压缓冲区里,则回复+CONTINUE
,表示主服务器将与从服务器执行部分重同步,从服务器只要等着主服务器将自己缺少的那部分数据发送过来就可以了; - 如果不能执行部分重同步,比如接收到的
runid
不是自己的运行ID,或者offset
偏移之后的数据已经不在复制积压缓冲区了,则回复+FULLRESYNC <runid> <offset>
,表示主服务器将与从服务器执行完整重同步:
runid
是主服务器的运行ID,从服务器会把这个ID保存起来,在下一次发送PSYNC
命令时使用;offset
是主服务器当前的复制偏移量,从服务器会将这个值作为自己的初始化偏移量;
- 如果主服务器的版本低于2.8,它不识别
PSYNC
命令,则回复-ERR
,从服务器将向主服务器发送低版本使用的SYNC
命令,与主服务器执行完整重同步。
3. 命令传播
- 在同步操作执行完毕后,主从服务器两者的数据库将达到一致状态,但是这种一致状态不是一成不变的,每当主服务器执行客户端发送的写命令时,主服务器的数据库就有可能被修改,并导致主从服务器状态不再一致;
- 为了让主从服务器再次回到一致状态,主服务器需要对从服务器执行命令传播操作:主服务器会将自己执行的写命令,也即造成主从服务器不一致的那条写命令,发送给从服务器执行,当从服务器执行了相同的写命令后,主从服务器将再次回到一致状态。
4. 复制的实现
复制主要由同步
和命令传播
组成,但是在进行这两步之前,还有其他一些操作,当从服务器执行了slaveof <master_ip> <master_port>
后,都执行了哪些操作呢?主要有以下步骤:
- 步骤1:设置主服务器的地址和端口
- 步骤2:建立套接字连接
- 步骤3:发送
PING
命令 - 步骤4:身份验证
- 步骤5:发送端口信息
- 步骤6:同步
- 步骤7:命令传播
4.1 步骤1:设置主服务器的地址和端口
- 从服务器将主服务器的IP(
<master_ip>
)和端口(<master_port>
)保存到服务器状态的masterhost
和masterport
属性里
struct redisServer{
// ...
// 主服务器的地址
char *masterhost;
// 主服务器的端口号
int masterport;
// ...
};
// 通过字段属性可以看出,一个从服务器只能指向一个主服务器;
4.2 步骤2:建立套接字连接
- 从服务器根据IP地址和端口号,创建连接向主服务器的套接字连接;
- 套接字成功连接到主服务器后,从服务器为这个套接字关联一个专门用于处理复制工作的文件事件处理器。(Redis是由事件驱动的,有文件事件和时间事件两类,文件事件是对套接字操作的抽象)
- 主服务器接受从服务器的套接字连接后,会为该套接字创建一个客户端状态,并将从服务器看作是一个连接到主服务器的客户端对待(主服务器要接收从服务器发送来的命令);
4.3 步骤3:发送PING命令
从服务器成为主服务器的客户端后(成功创建套接字连接后),做的第一件事就是向主服务器发送一个PING
命令,这个命令的作用:
- 检查套接字的读写状态是否正常;
- 检查主服务器是否正常处理命令请求;
从服务器发送完PING
命令后,会遇到三种情况的回复:
- 收到主服务器回复的
PONG
,表示主从服务器连接正常,可以继续执行复制工作的后续步骤; - 如果从服务器接收到主服务器回复的一个错误,表示主服务器当前暂时没法处理从服务器的命令请求,则不能继续执行复制工作的后续步骤,这种情况下,从服务器断开连接,并重新创建连向主服务器器的套接字;
- 如果从服务器不能在规定的时间内收到主服务器的回复,那么表示主从服务器之间的网络连接状态不佳(也可能是主机宕机,但是主机宕机大概率套接字连接都创建不成功),不能继续执行复制工作的后续步骤。当出现这种情况时,从服务器断开并重新创建连向主服务器的套接字;
4.4 步骤4:身份验证
- 从服务器在接收到主服务器返回的
PONG
回复后,下一步要做的就是决定是否进行身份验证:
- 如果从服务器设置了
masterauth
选项,那么进行身份验证; - 如果从服务器没有设置
masterauth
选项,那么不进行身份验证;
# masterauth后跟的是主服务器的密码
# masterauth <master-password>
- 在需要进行身份验证的情况下,从服务器会向主服务器发送一条
AUTH
命令,命令的参数为从服务器masterauth
选项的值。 - 身份认证也要根据主服务器是否开启了安全密码有关:
# requirepass foobared
- 如果主服务器没有设置
requirepass
,并且从服务器也没有设置masterauth
,那么不进行身份验证,继续执行复制工作后续的步骤; - 如果主服务器设置的
requirepass
和从服务器AUTH
命令携带的masterauth
值相同,则身份认证通过,继续执行复制工作后续的步骤; - 如果主服务器设置的
requirepass
和从服务器AUTH
命令携带的masterauth
值不相同,则身份认证不通过,主服务器返回一个invalid password
错误; - 如果主服务器没有设置
requirepass
,但是从服务器设置了masterauth
,则主服务器接收到AUTH
命令后身份验证不通过,会返回no password is set
错误; - 如果主服务器设置了
requirepass
,但是从服务器没有设置masterauth
,则身份验证不通过;
所有错误情况都会令从服务器中止目前的复制工作,并从创建套接字开始重新执行复制,直到身份验证通过,或者从服务器放弃执行复制为止;
4.5 步骤5:发送端口信息
在身份验证步骤后,从服务器将执行命令REPLCONF listening-port <port-number>
向主服务器发送从服务器的监听端口号;
主服务器在接收到命令后,会将端口号记录在从服务器所对应的客户端状态的slave_listening_port
属性中;
4.6 步骤6:同步
在这一步,从服务器将向主服务器发送PSYNC
命令,执行同步操作,并将自己的数据库更新至主服务器当前所处的状态。
注意:在同步操作执行之前,只有从服务器是主服务器的客户端(即,只有从服务器向主服务器发送命令),但是在执行同步操作之后,主服务器也会成为从服务器的客户端,因为:
- 如果
PSYNC
命令执行的是完整重同步,那么主服务器需要成为从服务器的客户端,才能将后台生成RDB文件过程中,保存在缓冲区里的写命令发送给从服务器执行; - 如果
PSYNC
命令执行的是部分重同步,那么主服务器需要成为从服务器的客户端,才能向从服务器发送保存在复制积压缓冲区里面的写命令;
4.7 步骤7:命令传播
当完成了同步之后,主从服务器就会进入命令传播阶段,这时主服务器只要一直将自己执行的写命令发送给从服务器,而从服务器只要一直接收并执行主服务器发送来的写命令,就能保证主从服务器的一致;
5. 心跳检测
在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送RELCONF ACK <replication_offset>
命令,其中replication_offset
是从服务器当前的复制偏移量。发送心跳检测的作用有三个:
- 检测主从服务器的网络连接状态
- 检测命令丢失
- 辅助实现主服务器的
min slaves
选项
检测主从服务器的网络连接状态
如果主服务器超过1秒钟没有收到从服务器发来的REPLCONF
命令,那么主服务器就知道主从服务器之间的连接出现问题了
检测命令丢失
如果因为网络故障,主服务器传播给从服务器的写命令在半路丢失,那么从服务器向主服务器发送REPLCONF ACK
命令时,主服务器就会发觉当前从服务器的偏移量少于自己的复制偏移量,然后主服务器就会根据从服务器提交的偏移量在复制积压缓存区里找到服务器缺少的数据,并将这些数据重新发送给从服务器,这称为补发缺少数据;
补发缺少数据和部分重同步的操作原理非常相似,区别在于,补发缺少数据是在主从服务器没有断线的情况下执行,而部分重同步则是在主从服务器断线并重连之后执行。
辅助实现min slaves
选项
主服务器可以在不安全的情况下拒绝执行写命令。当从服务器的个数小于设置值,或从服务器的延迟都大于或等于设置值时,主服务器认为不安全,将拒绝写命令;从服务器发送的心跳检测可以帮助主服务器统计从服务器的数量和各个从服务器的延迟;
min-slaves-to-write 3
min-slaves-max-lag 10
内容总结
以上是互联网集市为您收集整理的Redis主从复制过程详解全部内容,希望文章能够帮你解决Redis主从复制过程详解所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。