Redis高可用之主从复制原理演进分析
一、什么是主从复制
1.1 什么是主从复制
主从复制,从名字可以看出,至少需要 2 台 Redis 服务器,一台叫主 Redis 服务器,一台叫从 Redis 服务器,也可以把他们叫做主节点(主 Redis 服务器)从节点(从 Redis 服务器)。然后把主 Redis 服务器上的数据复制到从 Redis 服务器上,这就是主从复制。后续也会源源不断的把数据从主节点复制到从节点。
1.2 怎么设置主从复制
怎么设置主 Redis 服务器,怎么设置从 Redis 服务器?
比如有 2 台 Redis 服务器,ip 分别为:192.168.1.100 和 192.168.1.101。
- 第一种方法
比如将 192.168.1.100 这台服务器设置为主(master)服务器,那么就在服务器 192.168.1.101 的配置文件里设置如下:
replicaof 192.168.1.100 6379
然后重启服务器,这样主服务器就是 192.168.1.100,从服务器就是 192.168.1.101。
- 第二种方法
还可以用 redis-cli 客户端连接到 192.168.1.101,然后执行命令 replicaof 192.168.1.100 6379
。
这种方式如果从 Redis 重启后,主从关系就消失了。
- 第三种方法
在 redis-server 启动参数中增加 --replicaof 192.168.1.100 6379
参数
一台主服务器也可以有多台从服务器,从服务器也可以有从服务器。
二、为什么要主从复制
主从复制后就有多份数据,相当于有多个副本,既是备份也是容灾。
为什么要有主从复制功能?
其实问的就是 Redis 主从复制有什么作用,带来了啥好处。
- 负载均衡
数据量大的时候,为了减轻服务器压力,会用读写分离模式来分摊流量,主服务器负责写,从服务器负责读。当然主服务器也可以读。
- 故障恢复
主服务器出现问题时候,从服务器还可以继续提供服务。并且也可以把从服务器提升为主服务器,这就是 Redis 的哨兵模式。
高可用的数据冗余方式。
- 数据冗余
多了一份数据,故障了,就可以快速恢复数据。
三、怎么进行主从复制
3.1 主从复制同步的演进
在 Redis2.8 之前,都是全量数据复制。也就是说,断线重连后,也是重新全量复制数据。这种方式把很多原来同步过了的数据又重新同步一次,这种方式的数据同步效率太低。
在 Redis2.8 之后,增加了部分重同步模式,也就是增加增量数据同步,只同步需要同步的数据。这就改进了之前的数据同步模式。
什么时候进行全量数据同步?第一次数据同步时候就进行全量数据同步。有时主从数据不一致时也需要全量同步。
什么时候进行增量数据同步?比如断线重连后,就进行增量数据同步。
3.2 Redis2.8之前复制
Redis2.8 之前主从同步有 2 个部分:全量同步,命令传播。
流程图:
3.3 Redis2.8之后复制
Redis2.8 之后全量复制与上面(Redis2.8之前)复制步骤差不多,SYNC 命令变成了 PSYNC 命令,之后增加了部分重同步。部分重同步改进了之前的每次需要全量同步问题。
增加了部分重同步,这个要怎么做才能兼容之前的全量同步呢?怎么知道从库复制到哪儿了?第一个从库肯定要记录下从库复制到哪儿了,下次断线重连时就可以告诉主库该从哪个地方开始复制了。主库也要记录自己的一些复制信息。Redis 用了几个概念就把这些问题给解决了,Replication ID,offset,replication_backlog。
- Replication ID:复制 ID。这是一个较大的随机字符串,标记一个给定的数据集。每个主节点都会用这个 Repli ID 来标识内部数据集,从节点 ID。当从节点加入时,这个 repli id 就初始化了。
- offset:复制偏移量。每个主节点都有这个 offset 偏移量,主节点将自己产生的数据发送给从节点时,发送多少字节数据,自身 offset 就会增加多少。从节点也有自己 offset,从节点写入数据时,offset 也会增加。断线重连时,就可以知道从哪里开始同步了。offset 需配合下面的复制积压缓冲区工作。
- replication_backlog:复制积压缓冲区。它是在主节点上的一个环形缓冲区,用来存储主节点向从节点传递的命令。它是大小固定,存储的命令有限,所有超出了就会删除。从节点进行增量同步时,主节点会根据 offset 从 replication_backlog 中拷贝从节点缺失的数据到从节点。
Replication ID, offset,这一对来标识数据集版本。
Redis2.8之后就是用上面这几个概念实现部分数据重同步的。从节点发送主节点的 replid 和从节点的一个 offset,主节点拿到这个replid 和自己的 replid 比较,如果是一样,并且这个 offset 也在 backlog 中能找到,那就可以可以进行部分重同步。
全量复制步骤
- 主从节点先建立连接
建立连接后,从节点使用命令 PSYNC <replid> <offset>
向主节点发起同步请求。如果主从节点是第一次复制,那么命令为 PSYNC ? -1
,replid 为 ?,因为是第一次复制不知道主库的 replid。offset 为 -1,表示第一次复制。
主节点收到 PSYNC 命令后,会用 FULLRESYNC 命令响应,带上主节点的 replid 和 offset 返回给从库,从库会记录下这两个参数。便于以后判断是否需要部分重同步。
- 同步数据
主节点执行 bgsave 命令生成 RDB 文件,生成完后把文件发送给从节点,从节点加载 RDB 文件。这个过程中,主节点不会阻塞,依然会接收客户端的命令请求,当然,这些请求不会写在之前的 RDB 文件里,为了保持主从数据一致,这些命令会存储在 replication buffer 中,记录 RDB 文件后的所有写操作。
- 同步缓冲的命令数据
协商就是根据先前定义好步骤来发送相关命令,为同步做准备工作。有点协议的意思。步骤如下:
当主库把 RDB 文件传送给从节点完成后,就会把 replication buffer 中的写命令操作发送给从节点,从节点执行这些操作命令,主从节点同步完成。
- 命令传播
之后会继续向从节点发送主节点的操作命令,从节点执行这些命令,保持主从数据的一致。
上面是一个主体的同步步骤,更加详细的步骤要分析源码了。
发送步骤与 Redis2.8 之前全量同步没有多大区别。
部分数据同步
部分数据同步,解决的是主从节点在同步命令时候,网络断了在连上时,Redis2.8 之前会在全量同步数据,显然开销太大,不合理。能不能只把断线后的数据同步一份,而不是全量同步?
网络断线后,就有部分命令数据没有同步到从节点上去,那我们能不能保存这部分命令数据?重连后,将断开期间的这部分命令重新同步给从节点,这样就不需要全量同步。
Redis2.8 之后引入了 replication_backlog 复制积压缓冲区,前面有讲到这个概念。命令一方面会传输给从节点,另外还会记录在这个复制积压缓冲区里。Redis 使用一个环形缓冲区的结构保存最近的一些命令。在缓冲区中,对字节进行编号,这个编号在 Redis 中叫复制偏移量。
是否部分同步条件?
- 从节点 replid 和 主节点的 replid 相同
- 复制偏移量 offset 在复制积压缓冲区的 backlog_off 和 offset 范围之间。
如果满足上面的 2 个条件,就进行部分数据重同步。
四、Redis4.0的同源增量同步
先看两个问题
1.从节点重启后丢失了原主节点的节点编号和复制偏移量,这导致重启后需要全量复制,这个很好办,把这些信息保存下来
2.主从切换后,主节点信息变化了,导致从节点需要全量数据同步,这个也好办,只要能确认新主节点数据是从原主节点复制过来就可以了
Redis4.0 后,对 PSYNC 进行了改进,提出了同源增量复制解决方案,来解决上面提到的两个全量复制问题。
第1个:从节点重启后,需要跟主节点全量数据同步,为什么?本质原因,是从节点丢失了主节点的编号信息和偏移量信息。Redis4.0后,就把主节点的编号信息写入到 RDB 中持久化保存。
第2个:主从切换后,从节点需要和主节点全量同步,为什么?原因就是新的主节点不认识原来主节点的编号信息。切换后怎么才能识别到呢?Redis4.0 后,主从切换后,新的主节点会将先前的主节点信息记录下来,这样新主节点就知道自己原先数据是从哪个旧主节点同步来的,大家都是从同一个地方出来的,应该接受部分数据同步策略。
五、Redis6.0无盘同步复制
什么叫无盘?
原先的同步复制是通过 fork 一个子进程生成 RDB 快照文件,RDB 存储在磁盘上,然后传输 RDB 文件,从节点服务器在恢复 RDB 文件数据。
无盘,就是说不生成 RDB 文件,不通过 RDB 来传输数据。而是直接通过网络来传输数据。
怎么做到无盘呢?
Redis6.0 后,它也是先 fork 一个子进程,这个子进程 dump 数据,它通过管道回写给主节点,主节点在将数据发送给从节点,这样的过程就是无盘传输。
六、Redis7.0共享复制缓冲区
6.1 多从库时主库占用内存过多问题
(from: https://mp.weixin.qq.com/s/UlHksrqFq0yfKh1uMFvYNg 作者:shooterIT)
6.2 OutputBuffer 拷贝和释放的堵塞问题
- ReplicationBacklog 的限制
- OutputBuffer 拷贝和释放的堵塞问题
具体内容请看这里:https://mp.weixin.qq.com/s/UlHksrqFq0yfKh1uMFvYNg
6.3 解决方案:共享复制缓冲区
具体方案请看这里:https://mp.weixin.qq.com/s/UlHksrqFq0yfKh1uMFvYNg 作者:shooterIT
七、参考
- https://redis.io/docs/manual/replication/ redis 复制功能
- https://mp.weixin.qq.com/s/a4JTKKTCEyz1W0FIF5fVZA Redis 主从复制的演进历程与百度实践 - 百度
- https://mp.weixin.qq.com/s/UlHksrqFq0yfKh1uMFvYNg Redis 7.0 共享复制缓冲区的设计与实现-ShooterIT
- 《Redis设计与实现》