Garnet 集群复制
Garnet 集群支持遵循简单的主从(即主副本)模型的异步复制。这使得副本能够精确复制主副本。复制可以用于扩展读取操作,并通过将副本提升为主副本,从而减轻主副本故障的影响。在本页中,我们将概述复制协议,并讨论集群操作员可用的不同持久性/一致性选项。
Garnet 复制特性
Garnet 集群通过日志传输实现复制。主副本利用追加日志文件(AOF)记录插入/更新操作。一个专门的后台任务会遍历日志页面,并将其批量传输到相应的副本。副本将遍历接收到的日志页面,按顺序重放所有插入/更新操作,并生成自己的 AOF。主副本通常可以自由地进行任意检查点。当主副本进行检查点时,它会将一个检查点标记插入到 AOF 中。由此产生的副作用是,当任何附加的副本接收到相应的记录时,它将启动自己的检查点。因此,数据的精确版本由以下三元组标识:
[replication-id, checkpoint-version, replication-offset]
允许副本进行自己的检查点可以加快恢复过程,因为在常见情况下,副本可以从自己的检查点恢复并重放其 AOF,然后再连接到其主副本并恢复同步。在极少数情况下,副本必须通过从主副本检索最新检查点来执行完全同步。部分同步涉及从本地检查点(如果有)恢复,并且只重放主副本在相应检查点覆盖复制偏移量(CCRO)之后的 AOF 日志。完全同步涉及检索最新的主副本检查点并从中恢复,然后再开始接受任何新的 AOF 日志记录。
副本决定是否执行上述任何一种同步,具体如下:
- 如果主副本复制 ID 与副本复制 ID 不同,则必须进行完全同步。
- 如果主副本检查点版本与副本检查点不同,则必须进行完全同步。
- 如果以上条件都不成立,副本可以从本地检查点恢复,然后从 AOF 中缺少的偏移量继续重放。
复制性能与持久性选项
在正常工作负载下,AOF 日志会随着每次插入/更新操作而不断增长,直到进行检查点。新添加的 AOF 日志记录最初会驻留在内存中,然后随着新记录的添加而刷新到磁盘。对于写入密集型工作负载,这可能会严重影响主机的查询性能。此外,新配置的、添加到集群中的副本可能会面临更长的同步时间,因为它们必须从相应的 CCRO 开始重放 AOF 日志记录。
集群操作员可以在各种复制选项之间进行选择,以实现性能和持久性之间的权衡。这些选项的总结如下所示:
- 快速 AOF 截断 (FAT) 此选项强制主副本积极截断 AOF,使其不会溢出到磁盘。它可以与 aof-memory 选项结合使用,后者决定了最大 AOF 内存缓冲区大小。当副本连接到启用 FAT 的主副本时,AOF 不保证被截断,这可能导致写入丢失。为了克服这个问题,FAT 应该与 ODC 一起使用。
- 按需检查点(ODC)此选项强制主副本在副本尝试连接和恢复时,如果没有可用的检查点,则进行检查点。如果检查点可用或已可用,并且 CCRO 未被截断,则主副本将锁定它以防止在副本恢复时被截断。在这种情况下,当内存中的 AOF 缓冲区满时,AOF 日志可能会溢出到磁盘。在正常操作下,AOF 会被截断,不会发生溢出到磁盘的情况。
使用上述选项,我们保证在副本连接时不会丢失任何写入,并且复制保持高性能。然而,由于复制的异步性质,如果主节点意外宕机,副本可能尚未收到最新的 AOF 日志记录,从而导致写入丢失。
创建带有复制功能的 Garnet 集群
设置带复制功能的集群的过程与设置常规集群类似,同时还需要启用 aof 选项。这应该为集群中的每个实例完成。
GarnetServer.exe --cluster --checkpointdir='data/' --aof
AOF 日志文件存储在 checkpointdir 文件夹中,默认情况下是工作文件夹。默认情况下,每个 Garnet 实例都将扮演一个空的 Primary 角色。集群操作员必须最初将槽位分配给这些 Primary 的子集。其余实例可以通过使用 CLUSTER REPLICATE
命令转换为副本。下面显示了一个设置包含一个 Primary 和 2 个副本的集群的示例。
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7000 cluster myid
"15373cf386c5090a5f8a25f819c96b04a756381c"
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7000 cluster addslotsrange 0 16383
OK
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7000 cluster set-config-epoch 1
OK
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7001 cluster set-config-epoch 2
OK
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7002 cluster set-config-epoch 3
OK
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7000 cluster meet 192.168.1.26 7001
OK
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7000 cluster meet 192.168.1.26 7002
OK
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7001 cluster replicate 15373cf386c5090a5f8a25f819c96b04a756381c
OK
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7002 cluster replicate 15373cf386c5090a5f8a25f819c96b04a756381c
OK
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7000 cluster nodes
15373cf386c5090a5f8a25f819c96b04a756381c 192.168.1.26:7000@17000,DESKTOP-BT8KHK1 myself,master - 0 0 1 connected 0-16383
5868649e4205bf6ea97e4b7a12f101c3aed96b71 192.168.1.26:7001@17001,DESKTOP-BT8KHK1 slave 15373cf386c5090a5f8a25f819c96b04a756381c 0 0 4 connected
947692ec7fb4a919ae7d0d7e314e9dcbcbd99774 192.168.1.26:7002@17002,DESKTOP-BT8KHK1 slave 15373cf386c5090a5f8a25f819c96b04a756381c 0 0 5 connected
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7001 cluster nodes
5868649e4205bf6ea97e4b7a12f101c3aed96b71 192.168.1.26:7001@17001,DESKTOP-BT8KHK1 myself,slave 15373cf386c5090a5f8a25f819c96b04a756381c 0 0 4 connected
15373cf386c5090a5f8a25f819c96b04a756381c 192.168.1.26:7000@17000,DESKTOP-BT8KHK1 master - 0 0 1 connected 0-16383
947692ec7fb4a919ae7d0d7e314e9dcbcbd99774 192.168.1.26:7002@17002,DESKTOP-BT8KHK1 slave 15373cf386c5090a5f8a25f819c96b04a756381c 0 0 5 connected
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7002 cluster nodes
947692ec7fb4a919ae7d0d7e314e9dcbcbd99774 192.168.1.26:7002@17002,DESKTOP-BT8KHK1 myself,slave 15373cf386c5090a5f8a25f819c96b04a756381c 0 0 5 connected
15373cf386c5090a5f8a25f819c96b04a756381c 192.168.1.26:7000@17000,DESKTOP-BT8KHK1 master - 0 0 1 connected 0-16383
5868649e4205bf6ea97e4b7a12f101c3aed96b71 192.168.1.26:7001@17001,DESKTOP-BT8KHK1 slave 15373cf386c5090a5f8a25f819c96b04a756381c 0 0 4 connected
连接到给定主节点的副本数量没有限制。目前,我们不支持链式复制。
查询副本
默认情况下,副本只处理读取查询,但也可以配置为处理写入请求。此选项通过在单个客户端会话中执行任何写入操作之前,发出一次 READWRITE
命令来启用。发出 READONLY
命令将切换回处理读取查询。
如果副本设置为处理只读查询,它将对任何写入请求以 -MOVED 响应,将其重定向到正在复制的主节点。
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7001 -c
192.168.1.26:7001> set x 1234
-> Redirected to slot [16287] located at 192.168.1.26:7000
OK
192.168.1.26:7000> set x 1234
OK
192.168.1.26:7000> get x
"1234"
192.168.1.26:7000> exit
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7001 -c
192.168.1.26:7001> get x
"1234"
192.168.1.26:7001> exit
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7002
192.168.1.26:7002> get x
"1234"
检查点与恢复
如上所述,主副本可以进行任意检查点并将该信息传播到副本。副本将在 AOF 文件中识别检查点记录并自行启动检查点。在主副本上进行检查点就像调用 SAVE
或 BGSAVE
命令一样简单。当检查点操作完成时,它会被记录到 AOF 日志中。副本将接收该记录并自行启动检查点。
检查点传播的示例如下所示
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7000
192.168.1.26:7000> lastsave
(integer) 0
192.168.1.26:7000> bgsave
Background saving started
192.168.1.26:7000> lastsave
(integer) 1706555027
192.168.1.26:7000> exit
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7001
192.168.1.26:7001> lastsave
(integer) 1706555029
192.168.1.26:7001> exit
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7002
192.168.1.26:7002> lastsave
(integer) 1706555028
192.168.1.26:7002>
复制信息
系统管理员可以通过使用 info replication 命令检索复制信息部分来跟踪复制进度。下面显示了返回的可用字段摘要:
role:被查询实例的角色 connected_slaves:连接到该实例的副本数量。master_failover_state:正在进行的故障转移的状态(如果有)。master_replid:此 Garnet 服务器实例的复制 ID。master_replid2:辅助复制 ID(目前未使用)。master_repl_offset:当前主 AOF 偏移量。store_current_safe_aof_address:最新检查点覆盖的 AOF 地址。store_recovered_safe_aof_address:恢复的检查点覆盖的 AOF 地址。object_store_current_safe_aof_address:对象存储最新检查点覆盖的 AOF 地址。object_store_recovered_safe_aof_address:对象存储恢复的检查点覆盖的 AOF 地址。
192.168.1.26:7000> info replication
# Replication
role:master
connected_slaves:2
master_failover_state:no-failover
master_replid:dd194cb04b18b31373157e22d0ab36df9cc6a04a
master_replid2:
master_repl_offset:136
second_repl_offset:136
store_current_safe_aof_address:0
store_recovered_safe_aof_address:0
object_store_current_safe_aof_address:0
object_store_recovered_safe_aof_address:0
slave0:ip=192.168.1.26,port=7001,state=online,offset=136,lag=0
slave1:ip=192.168.1.26,port=7002,state=online,offset=136,lag=0
192.168.1.26:7000> exit
PS C:\Dev> redis-cli -h 192.168.1.26 -p 7001
192.168.1.26:7001> info replication
# Replication
role:slave
connected_slaves:0
master_failover_state:no-failover
master_replid:dd194cb04b18b31373157e22d0ab36df9cc6a04a
master_replid2:
master_repl_offset:136
second_repl_offset:136
store_current_safe_aof_address:0
store_recovered_safe_aof_address:0
object_store_current_safe_aof_address:0
object_store_recovered_safe_aof_address:0
master_host:192.168.1.26
master_port:7000
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:False
slave_read_repl_offset:136
slave_priority:100
slave_read_only:1
replica_announced:1
192.168.1.26:7001>
无盘复制
当 AOF 被截断时,完全同步需要进行检查点并将该检查点发送给正在附加的副本。此操作可能很昂贵,因为它涉及主副本和副本上的多个 I/O 操作。因此,我们添加了一种完全同步的变体,称为无盘复制。这是通过流式检查点实现的,允许客户端在附加副本同步时继续在主副本上发出读取和写入。要启用无盘复制,服务器需要使用以下标志启动:
--repl-diskless-sync=true 这用于启用无盘复制
--repl-diskless-sync-delay=<seconds>。这用于确定在开始完全同步之前等待多少秒,以便为多个副本提供附加并接收流式检查点的机会。
除了使用上述标志之外,利用无盘复制没有额外的要求。用于映射副本的 API 保持不变(即 CLUSTER REPLICATE、REPLICAOF 等)。
请注意,无盘复制不会进行实际的检查点。因此,每次执行完全同步时,AOF 不会自动截断(除非使用 FAT 标志)。这样做是为了确保在发生故障时的数据持久性,如果 AOF 在没有持久检查点的情况下被截断,这是不可能的。但是,存储版本会递增,以确保不同时间完全同步的不同实例之间的一致性。用户仍然可以使用 SAVE/BGSAVE 命令或 --aof-size-limit 定期进行检查点并安全地截断 AOF。