旧版复制功能的实现 --------------------------- Redis 的复制功能分为同步(sync)和命令传播(command propagate)两个操作: - 其中, 同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。 - 而命令传播操作则用于在主服务器的数据库状态被修改, 导致主从服务器的数据库状态出现不一致时, 让主从服务器的数据库重新回到一致状态。 本节接下来将对同步和命令传播两个操作进行详细的介绍。 同步 ^^^^^^^^^^^ 当客户端向从服务器发送 :ref:`SLAVEOF` 命令, 要求从服务器复制主服务器时, 从服务器首先需要执行同步操作, 也即是, 将从服务器的数据库状态更新至主服务器当前所处的数据库状态。 从服务器对主服务器的同步操作需要通过向主服务器发送 :ref:`SYNC` 命令来完成, 以下是 :ref:`SYNC` 命令的执行步骤: 1. 从服务器向主服务器发送 :ref:`SYNC` 命令。 2. 收到 :ref:`SYNC` 命令的主服务器执行 :ref:`BGSAVE` 命令, 在后台生成一个 RDB 文件, 并使用一个缓冲区记录从现在开始执行的所有写命令。 3. 当主服务器的 :ref:`BGSAVE` 命令执行完毕时, 主服务器会将 :ref:`BGSAVE` 命令生成的 RDB 文件发送给从服务器, 从服务器接收并载入这个 RDB 文件, 将自己的数据库状态更新至主服务器执行 :ref:`BGSAVE` 命令时的数据库状态。 4. 主服务器将记录在缓冲区里面的所有写命令发送给从服务器, 从服务器执行这些写命令, 将自己的数据库状态更新至主服务器数据库当前所处的状态。 图 IMAGE_SYNC 展示了 :ref:`SYNC` 命令执行期间, 主从服务器的通信过程。 .. graphviz:: digraph { label = "\n 图 IMAGE_SYNC 主从服务器在执行 SYNC 命令期间的通信过程" rankdir = LR splines = ortho node [shape = box, height = 2] master [label = "主\n服\n务\n器"] slave [label = "从\n服\n务\n器"] master -> slave [dir = back, label = "发送 SYNC 命令"] master -> slave [label = "\n 发送 RDB 文件"] master -> slave [label = "\n 发送缓冲区保存的所有写命令"] } 表 TABLE_SYNC_EXAMPLE 展示了一个主从服务器进行同步的例子。 +-------+-------------------------------------------+-----------------------------------------------+ | 时间 | 主服务器 | 从服务器 | +=======+===========================================+===============================================+ | T0 | 服务器启动。 | 服务器启动。 | +-------+-------------------------------------------+-----------------------------------------------+ | T1 | 执行 ``SET k1 v1`` 。 | | +-------+-------------------------------------------+-----------------------------------------------+ | T2 | 执行 ``SET k2 v2`` 。 | | +-------+-------------------------------------------+-----------------------------------------------+ | T3 | 执行 ``SET k3 v3`` 。 | | +-------+-------------------------------------------+-----------------------------------------------+ | T4 | | 向主服务器发送 :ref:`SYNC` 命令。 | +-------+-------------------------------------------+-----------------------------------------------+ | T5 | 接收到从服务器发来的 :ref:`SYNC` 命令, | | | | 执行 :ref:`BGSAVE` 命令, | | | | 创建包含键 ``k1`` 、 ``k2`` 、 ``k3`` | | | | 的 RDB 文件, | | | | 并使用缓冲区记录接下来执行的所有写命令。 | | +-------+-------------------------------------------+-----------------------------------------------+ | T6 | 执行 ``SET k4 v4`` , | | | | 并将这个命令记录到缓冲区里面。 | | +-------+-------------------------------------------+-----------------------------------------------+ | T7 | 执行 ``SET k5 v5`` , | | | | 并将这个命令记录到缓冲区里面。 | | +-------+-------------------------------------------+-----------------------------------------------+ | T8 | :ref:`BGSAVE` 命令执行完毕, | | | | 向从服务器发送 RDB 文件。 | | +-------+-------------------------------------------+-----------------------------------------------+ | T9 | | 接收并载入主服务器发来的 RDB 文件 , | | | | 获得 ``k1`` 、 ``k2`` 、 ``k3`` 三个键。 | +-------+-------------------------------------------+-----------------------------------------------+ | T10 | 向从服务器发送缓冲区中保存的写命令 | | | | ``SET k4 v4`` 和 ``SET k5 v5`` 。 | | +-------+-------------------------------------------+-----------------------------------------------+ | T11 | | 接收并执行主服务器发来的两个 :ref:`SET` 命令,| | | | 得到 ``k4`` 和 ``k5`` 两个键。 | +-------+-------------------------------------------+-----------------------------------------------+ | T12 | 同步完成, | 同步完成, | | | 现在主从服务器两者的数据库都包含了键 | 现在主从服务器两者的数据库都包含了键 | | | ``k1`` 、 ``k2`` 、 ``k3`` 、 ``k4`` 和 | ``k1`` 、 ``k2`` 、 ``k3`` 、 ``k4`` 和 | | | ``k5`` 。 | ``k5`` 。 | +-------+-------------------------------------------+-----------------------------------------------+ 命令传播 ^^^^^^^^^^^ 在同步操作执行完毕之后, 主从服务器两者的数据库将达到一致状态, 但这种一致并不是一成不变的 —— 每当主服务器执行客户端发送的写命令时, 主服务器的数据库就有可能会被修改, 并导致主从服务器状态不再一致。 举个例子, 假设一个主服务器和一个从服务器刚刚完成同步操作, 它们的数据库都保存了相同的五个键 ``k1`` 至 ``k5`` , 如图 IMAGE_CONSISTENT 所示。 .. graphviz:: digraph { label = "\n 图 IMAGE_CONSISTENT 处于一致状态的主从服务器" rankdir = LR node [shape = record, width = 2] subgraph cluster_master { label = "主服务器" master_db [label = "
数据库 |