Garnet 集群概述
Garnet 集群提供了一种在多个节点上轻松、可扩展地操作 Garnet 的方式。它支持多种功能,包括扩容/缩容、数据迁移和数据复制。本文档概述了分片机制和集群配置。
Garnet 集群分片
集群的键空间被分成 16384 个槽。任何给定的槽都由一个主 Garnet 实例拥有,任何给定的键都只映射到一个槽。如果选择配置 Garnet 进行复制,Garnet 实例可以作为副本运行,并为哈希到其对应主实例拥有的槽的键提供只读请求。所有单键操作都受 Garnet 集群支持。但是,多键操作仅在所有涉及的键都映射到单个槽时才进行处理。用户可以通过使用哈希标签将不同的键映射到同一个槽来克服此限制。如果键包含 {...},则只有括起来的字符串用于哈希函数计算。例如,键 {abc}xyz 和 xyz{abc} 将哈希到相同的哈希槽。
客户端重定向
客户端可以连接到集群中的任何节点并发出单键/多键操作或任何类型的集群管理操作。接收节点通过计算与相应操作关联的键的哈希槽值来处理单键/多键操作,并以下列方式之一进行响应
- 如果槽由接收节点拥有,它将执行实际操作,如同独立 Garnet 所期望的那样。
- 如果槽由另一个节点拥有,它将响应 -MOVED <slot> <address> <port>
- 如果接收节点是副本,它将仅处理其主节点拥有的槽的读取请求,并使用 -MOVED 消息将任何写入请求重定向到主节点。
- 如果槽由接收节点拥有且该槽正在迁移,则
- 如果键存在,则读取请求正常处理,而写入请求返回 -MIGRATING。
- 如果键不存在,则读取和写入请求返回 -ASK <slot> <address> <port>。
- 如果槽由另一个节点拥有且接收节点是迁移操作的目标,则
- 仅当事先发出 ASKING 后才处理读取和写入请求。请注意,如果使用 ASKING,则无法确保写入安全性,因此客户端在使用时应格外小心。
Garnet 集群配置
每个 Garnet 集群实例都保留集群配置的持久本地副本。配置更新可以通过集群命令直接应用于特定节点,或通过流言协议传播。
集群配置包含槽分配信息和集群中每个已知节点的信息。
有关集群配置的更多信息,请参阅 CLUSTER NODES 命令的描述。
控制平面
重要的是要记住,Garnet 的集群模式设计目前是被动的:这意味着它不实现领导者选举,而只是响应由独立的控制平面发出的集群命令。用户必须部署一个控制平面(例如 Kubernetes 中的操作员 [示例])来检测故障并请求故障转移。Garnet 本身尚未提供控制平面实现。构建强大的控制平面所需的所有命令都包含在 Garnet 中,我们的合作伙伴已经为 Garnet 的内部使用构建并部署了生产质量的控制平面实现。
这种关注点分离允许用户灵活地在各种平台(例如 Kubernetes、虚拟机规模集 和 Service Fabric)上部署 Garnet。这允许用户利用这些系统中可用的生产级领导者选举功能,以及用于管理 Garnet 集群的组件,例如用于元数据存储的可靠云数据库。
创建 Garnet 集群
在展示如何创建 Garnet 集群之前,我们将在下面简要概述与运行基本 Garnet 集群部署相关的最重要的参数。
- --port:运行服务器的端口。相同的端口用于处理查询和节点间通信。
- --bind:服务器绑定的 IP 地址
- --checkpointdir:当启用 --cluster 选项时,用于指定检查点位置和集群配置的路径。
- --cluster:启用集群模式
- --cluster-timeout:节点间通信超时。
- --gossip-delay:流言协议广播发送更新配置或 ping 已知节点的延迟。
- --gossip-sp:在每次流言迭代中,与集群节点的流言百分比
要创建 Garnet 集群,您首先需要使用 --cluster
选项运行 Garnet 实例,如下所示。使用 --checkpointdir
选项是可选的。此示例中包含它以避免配置文件之间的任何冲突。如果您不指定 --checkpointdir
选项,Garnet 将使用启动文件夹来保存任何关联的配置
GarnetServer --cluster --checkpointdir clusterData/7000 --port 7000
GarnetServer --cluster --checkpointdir clusterData/7001 --port 7001
GarnetServer --cluster --checkpointdir clusterData/7002 --port 7002
一旦实例启动并运行,您可以使用任何兼容 redis 的客户端来初始化集群以分配槽。
对于上述示例,我们使用 redis-cli 来演示集群如何初始化
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 --cluster-yes
一旦上述初始化完成,集群就可以处理客户端查询了。下面显示了一个如何使用已初始化集群的示例
PS C:\Dev> redis-cli -p 7000
127.0.0.1:7000> cluster nodes
ee337ebd15255c163b0d6faa4d055cdb26215938 127.0.0.1:7000@17000,hostname01 myself,master - 0 0 1 connected 0-5460
4f86082c3d3250c0dba0f925e71963d46974fbca 127.0.0.1:7002@17002,hostname02 master - 0 0 3 connected 10923-16383
cf333332b44a32fa70c30862b6d9535e9bac19f9 127.0.0.1:7001@17001,hostname03 master - 0 0 2 connected 5461-10922
127.0.0.1:7000> cluster keyslot x
(integer) 16287
127.0.0.1:7000> get x
(error) MOVED 16287 10.159.2.73:7002
127.0.0.1:7000> set x 1234
(error) MOVED 16287 10.159.2.73:7002
127.0.0.1:7000> cluster keyslot wxz
(integer) 949
127.0.0.1:7000> set wxz 1234
OK
127.0.0.1:7000> get wxz
"1234"
127.0.0.1:7000>
或者,可以使用 CLUSTER MEET、CLUSTER SET-CONFIG-EPOCH、CLUSTER ADDSLOTS 或 CLUSTER ADDSLOTSRANGE 和 CLUSTER REPLICATE 命令的组合手动或以编程方式配置集群。以下示例演示了如何初始化两个节点,将所有槽分配给其中一个,使节点相互认识,并将第二个节点配置为第一个节点的副本。
PS C:\Dev> redis-cli -p 7000 cluster nodes
d6c7f0c2a2839efad9a6578647d6456f90845836 127.0.0.1:7000@17000,localhost myself,master - 0 0 0 connected
PS C:\Dev> redis-cli -p 7001 cluster nodes
c65d29d420960fe5213ccb87ce1f74d7ee6ca4f1 127.0.0.1:7001@17001,localhost myself,master - 0 0 0 connected
PS C:\Dev> redis-cli -p 7000 cluster set-config-epoch 1
OK
PS C:\Dev> redis-cli -p 7001 cluster set-config-epoch 2
OK
PS C:\Dev> redis-cli -p 7000 cluster addslotsrange 0 16383
OK
PS C:\Dev> redis-cli -p 7000 cluster nodes
d6c7f0c2a2839efad9a6578647d6456f90845836 127.0.0.1:7000@17000,localhost myself,master - 0 0 1 connected 0-16383
PS C:\Dev> redis-cli -p 7001 cluster nodes
c65d29d420960fe5213ccb87ce1f74d7ee6ca4f1 127.0.0.1:7001@17001,localhost myself,master - 0 0 2 connected
PS C:\Dev> redis-cli -p 7000 cluster meet 127.0.0.1 7001
OK
PS C:\Dev> redis-cli -p 7000 cluster nodes
d6c7f0c2a2839efad9a6578647d6456f90845836 127.0.0.1:7000@17000,localhost myself,master - 0 0 1 connected 0-16383
c65d29d420960fe5213ccb87ce1f74d7ee6ca4f1 127.0.0.1:7001@17001,localhost master - 638875895159094739 0 2 connected
PS C:\Dev> redis-cli -p 7001 cluster nodes
c65d29d420960fe5213ccb87ce1f74d7ee6ca4f1 127.0.0.1:7001@17001,localhost myself,master - 0 0 2 connected
d6c7f0c2a2839efad9a6578647d6456f90845836 127.0.0.1:7000@17000,localhost master - 638875895161944429 0 1 connected 0-16383
PS C:\Dev> redis-cli -p 7001 cluster replicate $(redis-cli -p 7000 cluster myid)
OK
PS C:\Dev> redis-cli -p 7000 cluster nodes
d6c7f0c2a2839efad9a6578647d6456f90845836 127.0.0.1:7000@17000,localhost myself,master - 0 0 1 connected 0-16383
c65d29d420960fe5213ccb87ce1f74d7ee6ca4f1 127.0.0.1:7001@17001,localhost slave d6c7f0c2a2839efad9a6578647d6456f90845836 638875895309129088 638875895309125478 3 connected
PS C:\Dev> redis-cli -p 7001 cluster nodes
c65d29d420960fe5213ccb87ce1f74d7ee6ca4f1 127.0.0.1:7001@17001,localhost myself,slave d6c7f0c2a2839efad9a6578647d6456f90845836 0 0 3 connected
d6c7f0c2a2839efad9a6578647d6456f90845836 127.0.0.1:7000@17000,localhost master - 638875895311833070 638875895311830232 1 connected 0-16383
PS C:\Dev>
请注意,不需要使用 redis-cli;任何兼容 RESP 协议的客户端都可以执行上述命令。