Redis09_深入理解主从复制

Redis主从复制通过主节点同步数据到从节点,实现数据冗余、读写分离和备份。主节点处理写操作并同步数据,从节点处理读操作。复制过程包括全量/部分复制和命令传播。PSYNC2优化了故障转移后的部分重同步。全量复制使用RDB而非AOF以提高效率。但主从复制缺乏自动故障转移能力,需借助Redis Sentinel解决。

作品集: Redis学习
作者头像
LumiBee
22 天前 · 71 0
分享

主从复制

在最基础的Redis应用中,可能只有一个Redis实例,这种模式简单直接,但存在明显的风险:一旦实例宕机,所有依赖它的服务都会收到影响,并且数据可能丢失.为了解决这个问题,Redis引入了主从复制(Master-Slave Relication)

redis-replication-high-availability.png

定义

主从复制允许我们将一台 Redis 服务器(Master 主节点)的数据完整地、实时地复制到一台或多台其他的 Redis 服务器(Replica 从节点,旧称 Slave)。

  • Master (主节点): 负责处理客户端的写操作,并将数据变更同步给所有连接的从节点。它也可以处理读操作。
  • Replica (从节点): 通常配置为只读,从主节点接收数据更新。它可以处理客户端的读操作,从而分担主节点的读压力。

为什么使用主从复制

  • 数据冗余: 数据在多个节点上存在副本,即使主节点发生故障,数据依然存在于从节点,为数据恢复提供了保障。

  • 读写分离/读扩展: 将读请求分散到多个从节点,降低主节点的负载压力,提高应用的整体读性能。主节点可以更专注于处理写请求。

  • 数据备份: 可以在从节点上执行数据备份操作(如 BGSAVE),避免对主节点服务性能造成影响。

主从复制如何工作

  • 连接建立与同步: 从节点连接到主节点,发送同步请求 (PSYNC)。

  • 全量复制: 如果是首次连接或无法进行部分复制,主节点会生成RDB快照发送给从节点,从节点加载RDB并接收后续的增量命令。

  • 部分复制: 如果从节点之前连接过且满足条件(run_id 相同,offset 在复制积压缓冲区内),主节点只会发送断连期间缺失的命令。

    • master通过一个环形的**复制积压缓冲区(repl_backlog_buffer)**来记录从生产RDB文件开始收到的所有写命令来找到slave缺少的数据从而避免全量复制.一个master中只有一个复制积压缓冲区,master所有的slave共用
    • Real_backlog_buffer是一个固定长度的队列(FIFO,先进先出),默认大小为1MB,支持自定义大小
  • 命令持续传播: 同步完成后,主节点会将所有新的写命令实时异步地发送给从节点。

  • 心跳与ACK: 主从节点间通过 PING/ACK 机制维持连接并监控同步状态。

PSYNC的演进

  1. SYNC (Redis < 2.8):
  • 这是最早的复制命令。
  • 无论什么情况(初次连接、断线重连),都触发全量复制。效率低下。
  1. PSYNC (或称 PSYNC1, Redis 2.8 - 3.x):
  • 引入了部分重同步 (Partial Resynchronization) 的概念。
  • 核心依赖三个要素:
    • 主节点的运行ID (run_idmaster_replid): 一个随机字符串,主节点启动时生成。从节点会记录其主节点的 run_id
    • 复制偏移量 (offset): 主从双方都维护一个偏移量,表示已发送/已接收的复制流的字节数。
    • 复制积压缓冲区 (replication backlog): 主节点上一个固定大小的循环缓冲区,存储最近发送的写命令。
  • 工作流程:
    • 从节点连接主节点时,发送 PSYNC <master_run_id> <offset>
    • 主节点检查:
      • 如果 master_run_id 与自身的 run_id 匹配,并且 offset 之后的数据仍在积压缓冲区内,则执行部分重同步,只发送缺失的数据。
      • 否则,执行全量重同步 (+FULLRESYNC <new_run_id> <current_offset>)。
  • PSYNC1 的不足:
    • 如果主节点崩溃并重启,它的 run_id 会改变。即使数据可能大部分还在(通过持久化恢复),所有从节点也必须进行全量重同步。
    • 如果发生故障转移,一个从节点被提升为新的主节点,它的 run_id 与旧主节点不同。其他从节点连接到这个新主节点时,因为 run_id 不匹配,也必须进行全量重同步,即使新主节点的数据与它们之前复制的旧主节点数据有很大重叠。
  1. PSYNC2 (Redis 4.0+):

PSYNC2 的目标就是优化上述 PSYNC1故障转移场景下的不足,使得在主节点角色发生变化后,从节点仍有更大机会进行部分重同步。

  • 保留了 replid (原 run_id) 和 offset
    • 每个 Redis 实例(无论是主还是从)都有一个主复制ID (replid)。当一个实例成为主节点时,这个 replid 标识了它所生成的数据流的历史。从节点会继承其主节点的 replid
    • offset 仍然是这个 replid 历史中的字节偏移量。
  • 引入了 replid2second_repl_offset
    • 每个主节点现在还维护第二个复制ID (replid2)第二个复制偏移量 (second_repl_offset)
    • replid2 的作用: 当一个从节点被提升为新的主节点时(例如通过 Sentinel 或 Cluster 的故障转移),这个新的主节点会将其之前作为从节点时所复制的旧主节点的 replid 存储在自己的 replid2 中。同时,它也会记录一个 second_repl_offset,表示它从旧主节点那里复制到的偏移量。
    • 故障转移后的部分重同步:
      • 假设 MasterA (replid=A, offset=X) 宕机。
      • SlaveB (之前复制 MasterA,所以它也知道 replid=A 和自己同步到的 offset_B) 被提升为 NewMasterB。
      • NewMasterB 会生成一个新的自己的 replid (例如 replid=B),但它会把旧主节点A的 replid (即A) 存到自己的 replid2 中,并记录它从A同步到的偏移量 offset_B 作为 second_repl_offset
      • 现在,另一个从节点 SlaveC (之前也复制 MasterA,知道 replid=A 和自己同步到的 offset_C) 尝试连接到 NewMasterB。
      • SlaveC 发送 PSYNC A offset_C
      • NewMasterB 收到后,会检查:
        1. SlaveC 请求的 replid (A) 是否与自己的主 replid (B) 匹配or不匹配。
        2. 关键:SlaveC 请求的 replid (A) 是否与自己的第二个 replid (replid2) (即A) 匹配or匹配!
        3. 如果匹配,并且 SlaveC 请求的 offset_C 在 NewMasterB 的 second_repl_offset (即 offset_B) 范围内,并且 NewMasterB 的复制积压缓冲区中包含了从 offset_Coffset_B 这段属于旧主节点A历史的命令,那么就可以进行部分重同步。NewMasterB 会先发送这部分属于旧主节点历史的命令,然后再发送自己成为主节点后产生的新命令

为什么主从全量复制使用RDB而不是AOF

  • RDB文件存储的内容是经过压缩的二进制数据,文件很小.而AOF文件存储的是每一次写命令,类似于MySQL的binlog日志,通常会比RDB文件大很多.因此,传输RDB文件更节省带宽,速度也更快
  • 使用RDB文件恢复数据,直接解析还原数据即可,不需要一条一条地执行命令,速度非常快,而AOF则需要依次执行每个写命令,速度非常慢.也就是说,在恢复大数据集的时候,RDB的速度要更快
  • AOF需要选择合适的刷盘策略,如果刷盘策略选择不当的话,会影响Redis的正常运行.并且,根据所使用的刷盘策略,AOF的速度可能会慢于RDB

局限性

虽然主从复制提供了数据冗余,但它本身并不具备自动故障转移的能力。如果主节点宕机,需要人工介入,选择一个从节点提升为新的主节点,并修改其他从节点和客户端的配置。这个过程既不及时也容易出错。

为了解决这个问题,我们需要一个更加高效的工具——Redis Sentinel

阅读量: 71

评论区

登录后发表评论

正在加载评论...
相关阅读

暂无相关文章推荐

返回首页浏览更多文章