在互联网大厂的后端开发领域,Redis 作为一款高性能的内存数据库,被广泛应用于缓存、消息队列等场景。而 Redis 集群中的主从复制机制,更是保障数据安全、实现读写分离以及提升系统性能的关键所在。今天,就让我们一同深入探究 Redis 集群主从复制的实现方式。
Redis 主从复制的基础概念
在 Redis 集群中,存在着主节点(Master)和从节点(Slave)。主节点负责处理所有的写操作,而从节点则主要承担读操作,以此实现读写分离,提升系统的并发处理能力。同时,主节点会将数据同步给从节点,实现数据的冗余备份,增强数据的安全性。每个从节点只能有一个主节点,而一个主节点可以拥有多个从节点,数据的复制是单向的,由主节点流向从节点。
主从复制的搭建方式
(一)配置文件方式
在从节点的配置文件中加入slaveof {masterHost} {masterPort} (Redis 5.0 之前),在 Redis 5.0 及之后的版本是replicaof {masterHost} {masterPort},这种方式在重启之后仍然生效,是比较推荐的做法。例如:replicaof 192.168.1.101 6379 ,这就指定了该从节点要连接的主节点的 IP 地址和端口号。
(二)启动命令方式
在redis-server启动命令时加入--slaveof {masterHost} {masterPort} (Redis 5.0 之前),Redis 5.0 及之后为--replicaof {masterHost} {masterPort}。但这种方式重启后不会生效。比如:redis-server --replicaof 192.168.1.101 6379 --masterauth 123456 ,这里不仅指定了主节点,还设置了主节点的密码(如果主节点有密码的话)。
(三)命令行方式
直接在从节点的命令行中使用slaveof {masterHost} {masterPort} (Redis 5.0 之前),Redis 5.0 及之后使用replicaof {masterHost} {masterPort} 。同样,这种方式重启后也不会生效。若要断开从节点与主节点的连接,在从节点执行slaveof no one (Redis 5.0 之前),Redis 5.0 及之后为replicaof no one 即可。
主从复制的模式
(一)一主一从
这是最为简单的结构,主要用于在主节点出现宕机时,从节点能够迅速提供故障转移支持,直接转变为主节点。当应用的写命令并发量较高且需要持久化时,可以选择只在从节点上开启 AOF(Append Only File),这样既能保证数据安全性,又可避免持久化操作对主节点性能产生干扰。不过需要注意的是,如果主节点宕机,应避免其重启,以免出现数据过时错误。
(二)一主多从
对于读命令量大的场景,这种结构十分适用。客户端无需都从主节点读取数据,可以将客户端的请求流分散到其他从节点,实现负载均衡。例如,在一些大型电商网站的商品详情页缓存中,大量的读请求可以通过多个从节点来分担,提升系统的响应速度。
(三)树形主从
在一主多从结构中,若读请求过大,从节点设置过多,主节点的性能开销会显著增大,因为它既要将数据复制到多个节点,又要处理读写请求。而树形主从结构通过层级划分,将数据复制的压力分摊到从节点集合中,在一定程度上降低了主节点的性能开销,减少了主节点的数据复制传输次数。比如在一个大型社交平台中,海量的用户动态缓存读取需求,通过树形主从结构可以更好地应对。
主从结点数据复制的流程与原理
(一)psync 数据同步
psync 命令专门用于主从复制,它支持两种复制方式:
- 全量复制:一般用于初次数据同步,早期 Redis 版本仅支持此方式。此时,主节点会将全部数据发送给从节点。若主节点数据量过大,该操作的开销会非常大。例如,当一个新的从节点加入到数据量达数 GB 的 Redis 集群时,全量复制可能需要较长时间才能完成。
- 增量复制:当从节点因特殊情况宕机后重启,只需主节点补发部分宕机时遗漏的数据。从节点会发送当前自身的 replid(每个 Redis 服务器启动时自动生成的唯一标识)和 offset(用于表示从节点与主节点的同步情况),主节点依据这些信息判断执行全量复制(FULLRESYNC)还是增量复制(CONTINUE)。若遇到非预期情况,则返回 ERR 拒绝请求。Redis 主节点中有一个全局积压缓冲区,具体采用全量复制还是增量复制,取决于该全局缓冲区数据是否达到上限。若达到上限,进行全量复制;反之,直接通过全局积压缓冲区将数据同步给从节点。
psync 语法为:psync replicationid offset 。若replicationid为?且offset为-1,则进行全量复制;若replicationid和offset设置为具体值,则进行增量复制。
(二)主从服务器第一次同步的过程
可分为三个阶段:
第一阶段:建立链接、协商同步
执行replicaof命令后,从服务器会向主服务器发送psync命令请求数据同步,该命令包含主服务器的runID(每个 Redis 服务器启动时自动生成的随机 ID)和复制进度offset 。首次同步时,由于从服务器不知道主服务器的runID,所以设为? ,offset设为-1 。主服务器收到psync命令后,会用FULLRESYNC作为响应命令返回,同时带上自身的runID和当前的复制进度offset 。从服务器接收后记录这两个值,此阶段为全量复制做准备。
第二阶段:主服务器同步数据给从服务器
主服务器执行bgsave命令生成 RDB 文件(默认方式,首次全量时采用 RDB 文件,因其为二进制格式,可节省传输带宽且执行速度快,当然也可采用 AOF 文件),然后将文件发送给从服务器。从服务器收到 RDB 文件后,先清空当前数据,再载入该文件。需要注意的是,主服务器生成 RDB 文件的过程不会阻塞主线程,因为bgsave命令是由子进程异步完成的,在此期间 Redis 仍可正常处理命令。但此时主从服务器间的数据会出现不一致,因为此期间的写操作命令未记录到刚生成的 RDB 文件中。为保证数据一致性,主服务器会在生成 RDB 文件期间、发送 RDB 文件给从服务器期间以及从服务器加载 RDB 文件期间,将收到的写操作命令写入到replication buffer(所有同步到从服务器的命令都会经过该缓冲区)缓冲区中。
第三阶段:主服务器发送新写操作命令给从服务器
主服务器生成的 RDB 文件发送完毕,从服务器收到并丢弃所有旧数据,载入 RDB 数据到内存后,向主服务器回复确认消息。接着,主服务器将replication buffer缓冲区中记录的写操作命令发送给从服务器,从服务器执行这些命令,此时主从服务器的数据达到一致。
(三)主从服务器第一次同步完成后
主从服务器在完成第一次同步后,会基于长连接进行命令传播。具体流程如下:
- 接收命令:当主节点接收到一个写命令时,首先会将该命令写入Replication Buffer(实时数据),因为该缓冲区主要用于缓存当前的写操作,以便迅速将命令发送给连接的从节点。
- 发送命令:主节点会尝试立即将Replication Buffer中的命令发送给其所有活跃的从节点。若从节点连接正常,命令会快速传递。
- 写入Repl Backlog Buffer:同时,主节点也会将相同的写命令写入Repl Backlog Buffer 。Repl Backlog Buffer是一个 “环形” 缓冲区,用于处理从节点与主节点之间的网络延迟和临时断开的情况,它会缓存主节点的命令,以便在从节点重新连接后获取这些命令并进行同步。其有几个重要指标,如replication offset,用于标记缓冲区的同步进度,主从服务器都有各自的偏移量,主服务器使用master_repl_offset记录自己 “写” 到的位置,从服务器使用slave_repl_offset记录自己 “读” 到的位置。
Replication Buffer与Repl Backlog Buffer的区别:
- 实时性:Replication Buffer专注于存储最新的写命令,只包含主节点当前运行周期内接受的写操作,不包含历史操作或从节点断开连接期间的命令;而Repl Backlog Buffer存储过去一段时间内的写操作,用于从节点在重新连接后获取遗漏的命令。
- 缓冲区的生命周期:当新的写命令到达主节点时,写入Replication Buffer,若从节点连接正常,主节点立即将命令发送到从节点,其中的命令会被及时消费;而Repl Backlog Buffer是持续缓存一定时间内的写操作。
- 存储范围:Replication Buffer内容是瞬时的,代表当前正在进行的写操作;Repl Backlog Buffer则存储过去的写操作。
- 目的不同:Replication Buffer主要为提高写操作的实时性和效率,确保主节点能迅速响应写请求;Repl Backlog Buffer用于处理网络波动或从节点断连的情况,确保从节点恢复连接后能同步所有遗漏的写操作。
主从复制的常见问题及优化
(一)常见问题
- 复制风暴:在特定情况下,Redis 主从复制过程出现异常,导致网络带宽被大量占用、从节点延迟严重甚至同步失败。其成因主要包括大量从节点同时启动复制、网络延迟或不稳定以及主节点写入操作频繁等。例如,在一次系统升级后,大量新的从节点同时启动进行复制,导致网络带宽瞬间被占满,整个系统出现卡顿。
- 数据不一致:可能由于网络问题、复制延迟等原因导致主从节点数据不一致。比如在网络不稳定的情况下,主节点的部分写操作命令未能及时同步到从节点。
- 复制超时:从节点在规定时间内未完成与主节点的数据同步,可能是由于网络延迟、数据量过大等因素造成。
(二)优化措施
- 复制缓冲区调整:增大 master 节点的client-output-buffer-limit配置项阈值(或调整为不限制),增大repl_timeout配置项阈值,使 slave 节点有足够时间恢复 RDB 快照并且不会被动断开连接。同时,单个主机节点内尽量不再部署多个 master 节点,防止主机因意外情况导致所有 slave 节点的全量同步请求发送至同一主机内,还可以适当减少 slave 节点个数,或调整 slave 架构层级(在 Redis 4.0 版本之后,sub - slave 订阅 slave 时将会收到与 master 一样的复制数据流)。
- 启用无盘复制:主节点不进行磁盘 IO 写入,直接将数据通过网络传输给从节点,可减少磁盘 IO 开销,提升复制效率。
- 合理调整复制积压缓冲区:针对从节点断开重连场景,若复制积压缓冲区过小,可能导致全量复制。应根据实际业务情况合理设置其大小,确保从节点断开重连后能通过该缓冲区进行增量复制。
总结
在互联网大厂后端开发中,深入理解和熟练运用 Redis 集群的主从复制机制,对于构建高性能、高可用的系统至关重要。希望通过本文的介绍,能让大家对 Redis 主从复制有更全面、深入的认识,在实际工作中更好地发挥 Redis 的优势。