Redis 主从机制

Posted 飞鱼的梦呓

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis 主从机制相关的知识,希望对你有一定的参考价值。

阅读本文大约需要 6 分钟


这篇文章来聊聊 Redis 主从同步机制。


首先,需要明确主从集群的由来

从一个数据库系统的高可用角度来看,只有通过冗余才能保证高可用。再者,就算是把 Redis 当成缓存来使用,数据丢失了无所谓,但单机场景下存储的数据量上来以后也存在着性能瓶颈问题。


首先,需要声明的是主节点指的是能提供读写请求的节点,从节点指的是只提供读请求的节点。

主从集群就可以解决上面提到的两个问题,首先来看高可用,当主机宕机后,可以将其他的从机转变成主机继续提供服务。查询方面,从机可以分担读操作的请求,减轻主服务器的访问压力。

那么,为什么采用一主多从的架构呢?把集群中的节点都设置为主节点不是还可以分担写请求的压力吗?

这里可以采用假设法解释,如果一个集群中存在多个主节点,如果某个时刻有多个客户端在对相同的 key 操作,那么后面这个 key 在节点间同步时,就不知道要保存哪个值了。因此,非特殊情况下,数据库集群都是采用一主多从的读写分离模式提供服务。


了解完集群架构模式后,下面再来看看 Redis 中主从之间具体的同步机制吧。


Redis 主从同步阶段存在三个阶段


第一阶段

在从库上通过执行 replica of $master_host $master_port 命令与主库建立连接。

连接建立后,从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。psync 命令包含了主库的 runID 和复制进度 offset 两个参数。其中 runID,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为“?”。offset,此时设为 -1,表示第一次复制。

主库收到 psync 命令后,会用 FULL RESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。从库收到响应后,会记录下这两个参数。


第二阶段

主库通过 bgsave 命令生成 rdb,再将 rdb 快照传给从库,从库收到数据后,清空本地数据库,再加载主库传过来的 rdb 文件。

注:此时主库仍然在正常接收客户端请求,所有的客户端写操作都会记录在 replication buffer 中。


第三阶段

由于第二阶段,在 rdb 传输给从库的过程中,主库有可能新增或修改了数据,因此,在这一步,需要将第二阶段主库 replication buffer 的数据进行同步,这时主从库的数据就保持一致了。


第一次同步复制的流程图如下

第一次同步完成之后,从库后续再通过 psync $masterID $offsetID 进行数据同步(长连接命令传播)。


现在来思考一个问题,由于主从复制是基于网络传输的,那么当出现网络中断或延迟时,断连阶段的数据该如何处理呢?

在 Redis 2.8 之前,如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。听起来好像不可思议,但确实是如此,系统都是慢慢迭代优化的嘛。

在 2.8 版本之后,主从库会采用增量复制的方式继续同步,只会把主从库网络断连期间主库收到的命令,同步给从库。


增量同步的关键点就在于  repl_backlog_buffer 里面,先来介绍下概念。

repl_backlog_buffer 是一个环形缓冲区(有点像 mysql 的 redo log),主库会记录自己写到的位置,从库则会记录自己已经读到的位置。

刚开始的时候,主库和从库的写读位置在一起,这算是它们的起始位置。随着主库不断接收新的写操作,它在缓冲区中的写位置会逐步偏离起始位置,我们通常用偏移量来衡量这个偏移距离的大小,对主库来说,对应的偏移量就是 master_repl_offset。主库接收的新写操作越多,这个值就会越大。

从库在复制完写操作命令后,它在缓冲区中的读位置也开始逐步偏移刚才的起始位置,此时,从库已复制的偏移量 slave_repl_offset 也在不断增加。正常情况下,这两个偏移量基本相等。

当主从库的连接恢复后,从库会通过 psync 命令将当前的 slave_repl_offset 发给主库,主库根据自己的 master_repl_offset 计算出增量复制的数据发送给从库。


增量复制的流程图如下

上图中的 repl_backlog_buffer 是一个环形缓冲区,在缓冲区写满后,主库会继续写入,此时,就会覆盖掉之前写入的操作。如果从库的读取速度比较慢,就有可能导致从库还未读取的操作被主库新写的操作覆盖了,这会导致主从库间的数据不一致。

为了避免上述情况发生,可以通过调整 repl_backlog_buffer 的大小。


参考

《极客时间-Redis 核心技术与实战》


总结

为了实现 Redis 服务的高可用,可以使用主从集群,主从第一次复制执行流程可以分为三个步骤。

在主从网络发生故障时,Redis 2.8 之后的版本支持增量复制,核心是通过 repl_backlog_buffer 来实现,但需要注意控制好 repl_backlog_buffer 的大小,如果设置不合理,就会导致主库将从库还未及时同步的数据给覆盖掉,最终导致主从数据不一致。

以上是关于Redis 主从机制的主要内容,如果未能解决你的问题,请参考以下文章

深入剖析redis主从同步机制

Redis-----初识Redis-----主从复制.读写分离,主从切换(哨兵机制)

redis系列之主从复制与哨兵机制

redis主从同步机制

Redis 主从机制

Redis主从复制机制详解