最近我们的一个服务要解决一个主节点向从节点同步数据的问题,就来翻了翻书,研究了下redis是怎么实现主从同步的,来总结一下
今天先来说一下2.8版本之前是如何实现的
redis中,实现主从复制的方式主要有两种
1.配置文件中设置slaveof选项
- 在从服务器的配置文件配置slaveof选项
- 配置如下:
slaveof <masterip> <masterport>
- masterip 为redis主服务器的ip
- masterport 为redis主服务的redis服务端口
2.从服务器上使用客户端发送slaveof命令
- 使用客户端,连接到从服务器上
- 在从服务器上发送slaveof命令
- 命令如下:
slaveof masterip masterport
- masterip 为redis主服务器的ip
- masterport 为redis主服务的redis服务端口
redis主从同步功能的原理
- redis的主从同步功能主要分为两个操作
- 同步(sync)操作
- 命令传播(command propagate)两个操作
- 同步(sync)操作主要作用是将当前从服务器的状态更新至主服务器的状态,也就是把当前主服务器中的所有数据同步至从服务中
- 命令传播(command propagate) 使用同步(sync)操作完成后,主服务器会把所有执行的命令传递到从服务器,让主从保持一致
先说说同步(sync)操作
- 当从服务器向主服务器发送slaveof命令时,要求同步主服务事,会先执行同步(sync)操作,主要作用是将当前从服务器的状态更新至主服务器的状态,也就是把当前主服务器中的所有数据同步至从服务中
- 同步(sync)操作的流程如下
同步(sync)操作的流程
- 1.从服务器向主服务器发送slaveof命令
- 2.主服务器接受到slaveof命令后
- 3.开始执行BGSAVE命令
- 4.在后台生成一个RDB文件
- 5.并使用一个缓冲区记录从开始执行的所有命令
- 6.主服务器BGSAVE命令执行完毕
- 7.主服务器将BGSAVE命令生成的RDB文件发送至从服务器
- 8.从服务器接受RDB文件并且载入
- 9.将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态
- 10.主服务器将记录在缓冲区中里所有的写命令发送给从服务器
- 11.从服务器执行这些命令完成整个同步过程
再说说命令传播(command propagate) 操作
- 当同步(sync)操作执行完毕后,此时,主从服务器的数据库状态达到了一致状态
- 然后主服务器会将自己执行的写命令发送给从服务器,从服务器会执行主服务器发过来的命令,来实现同步,就是传播(command propagate) 操作
借用书上图举个整体流程的例子
时间 | 主服务器 | 从服务器 |
---|---|---|
T0 | 执行 SET K1 V1 命令 | |
T1 | 执行 SET K2 V2 命令 | |
T2 | 向主服务器发送slaveof命令 | |
T3 | 1.主服务器接受到slaveof命令后 2.开始执行BGSAVE命令 3.在后台生成一个RDB文件,包含K1、K2 4.并使用一个缓冲区记录从开始执行的所有命令 | |
T4 | SET K3 V3,并把命令写入缓冲区 | |
T5 | SET K4 V4,并把命令写入缓冲区 | |
T6 | BGSAVE命令执行完毕,向从服务器发送RDB文件 | |
T7 | 接收并载入主服务器发来的RDB文件, 获得K1、K2数据 | |
T8 | 向从服务器发送缓冲区中的SET K3 V3、 SET K4 V4 | |
T9 | 接收并执行主服务器发来的两个命令, 执行了SET K3 V3、SET K4 V4命令 | |
T10 | 同步(sync操作完成),此时主服务器中有K1、K2、K3、K4 四个key | 同步(sync操作完成),此时主服务器中有K1、 K2、K3、K4 四个key,数据库状态同步一致 |
T11 | 执行 SET K5 V5 命令,并且命令传播(command propagate) 把命令传递给从服务 | 执行主服务器传递过来的 SET K5 V5 命令 |
T12 | 执行 SET K6 V6 命令,并且命令传播 (command propagate) 把命令传递给从服务 | 执行主服务器传递过来的 SET K6 V6 命令 |
T13 | 主从服务器断开连接,并重连成功 | 主从服务器断开连接,并重连成功 |
T14 | 重新开始同步(sync)操作,重复上述流程 |
2.8版本之前主从同步的缺陷
- 2.8版本之前主从同步存在一些缺陷
- 按照上面的表格
- 如果是初次主从同步,是没有问题的
- 如果同步(sync)操作完成后,同步了K1、K2数据,此时,主从服务器之间处于命令传播 (command propagate) 阶段,传递了K3、K4命令,然后主从服务器之间断开连接
- 当主从服务器重新建立连接后,主从服务器之间又开始执行同步(sync)操作
- 此时的同步(sync)操作,主服务器生成RDB文件,RDB文件包含的key是从第一次同步中的K1开始,包含K1、K2、K3、K4
- 虽然还是可以完成同步(sync)操作,但是其实有很多key是没有必要再次同步的
- 因为同步(sync)操作中,需要主服务器生成RDB文件,这个操作会占用服务器的大量的资源:CPU、内存、IO
- 而主从服务器之间传递RDB文件会占用服务器带宽
- 从服务器加载RDB文件时,同样会占用服务器的大量的资源:CPU、内存、IO
- 所以没有没有必要的同步(sync)操作会损耗服务器资源,降低服务的性能
今天讲了redis的主从同步中的2.8版本以前的方式,最后说了2.8版本以前的方式中的一些缺陷,下次再来讲讲2.8版本以后的方式,欢迎大家来交流,指出文中一些说错的地方,让我加深认识,愿大家没有bug,谢谢!