From e47dc4711eeb1baac6e3fcd9831d64edafe2dce8 Mon Sep 17 00:00:00 2001 From: asahi Date: Mon, 29 Sep 2025 13:50:13 +0800 Subject: [PATCH] =?UTF-8?q?doc:=20=E9=98=85=E8=AF=BBredis=20cluster?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 中间件/redis/redis.md | 72 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/中间件/redis/redis.md b/中间件/redis/redis.md index e6a2a91..f90fc36 100644 --- a/中间件/redis/redis.md +++ b/中间件/redis/redis.md @@ -212,6 +212,10 @@ - [CLUSTER NODES](#cluster-nodes) - [Cluster bus](#cluster-bus) - [Cluster topology](#cluster-topology) + - [node handshake](#node-handshake) + - [Redirection and Resharding](#redirection-and-resharding) + - [MOVED Redirection](#moved-redirection) + - [Live reconfiguration](#live-reconfiguration) # redis @@ -3385,4 +3389,72 @@ redis cluster是一个`full mesh`结构,集群中每个node都和其他所有 redis cluster nodes组成了full mesh,但是node使用了`gossip protocol`和`configuration update mechanism`用于避免`nodes之间的消息交换过于频繁`。故而,消息交换的数量并非指数级增长。 +#### node handshake +node会从cluster bus port接收连接,当接收到ping时会返回响应,即使发出ping的node并不可信。除了ping packet之外,如果接收方node认为发送方节点并不是cluster中的一员,那么接收方会丢弃所有发送方除了ping packet之外的packets。 + +只有在如下两种场景下,一个node才会将应一个node认作集群的一部分: +- 如果一个节点通过`MEET` message来展示其自身(CLUSTER MEET命令)。meet message和`PING` message类似,但是会强制接收方将其作为cluster的一部分来接受。只有当系统管理员通过`CLUSTER MEET ip port`命令来发送请求时,node才向其他nodes发送meet message。 +- 如果一个已经受信任的节点通过gossip传播了关于`node C`的消息,那么其他节点也会将`node C`注册为集群的一部分。 + - 例如,`A knows B`,`B knows C`,最终B会向A发送关于C的gossip messages。当该行为发生时,A会将C注册为network的补一份,并且尝试和C建立连接 + +上述示例代表,只要将节点加入到`connected graph`,其最终自动会形成一个`fully connected graph`(尚未连接的nodes会两两自动建立连接)。在cluster中,只要管理员强制建立信任关系,节点能够自动发现其他节点。 + +### Redirection and Resharding +#### MOVED Redirection +一个redis client可以向cluster中所有的节点发送请求,包括replica nodes。该node会分析请求,如果请求时可接受的(在query中只有一个key,或多个key被hash到相同的slot中),那么其会分析key由哪个node负责: +- 如果node本身负责该slot,那么该请求将会被执行 +- 否则,node将会向client返回`MOVED error`,示例如下所示: + ```redis-cli + GET x + -MOVED 3999 127.0.0.1:6381 + ``` + +上述error代表key对应的hash slot(3999)和负责该key实例的`endpoint:port`值。client需要重新向`endpoint:port`发送请求。 +> 上面示例中,`endpoint`可以是一个ip address,hostname,或可以为空(`-MOVED 3999 :5380) +> - 当endpoint为空时,代表server node拥有unknown endpoint,client应该将下一个请求发送给`当前请求的endpoint`,但是使用响应中的port + +在client重新发送请求之前,如果间隔时间较长,此时cluster configuration可能会发生变动,此时再发送请求,如果负责该key的节点发生变化,目前节点仍可能会返回一个MOVED error。 + +client不必须,但是应该记住`hash slot 3999被127.0.0.1:6381管理`。之后如果新command对该hash slot发送请求,那么其可以直接针对正确的节点发送请求,避免重定向带来的开销。 + +对client而言,另一个可选项是`在接收到MOVED redirection之后,通过CLUSTER SHARDS命令清空整个client-side cluster layout`。通常而言,当遇到重定向时,更可能是多个slots都被reconfigured,此时尽快更新client configuration是更好的策略。 + +当集群处于稳定状态下时,最终所有客户端都会获取到`map of hash slots`,确保cluster效率更高,client无需重定向就能查询到正确的nodes。 + +#### Live reconfiguration +Redis Cluster支持在运行时动态添加、移除nodes的能力。对redis cluster而言,节点的增加和移除被抽象为相同的行为:`moving a hash slot from one node to another`。上述机制也能被用于cluster的rebalance。 +- 将新节点添加到cluster时,`some set of hash slots from existing nodes`将会被移动到新的节点 +- 将节点从cluster中被移除时,`hash slots assigned to that node`将会被移动到其他的existing nodes +- 在cluster进行rebalance时,`a given set of hash slots`将会在节点之间进行移动 + +实现上述内容的核心是`hash slots的移动`。从实际角度来看,hash slots是一系列keys的集合,故而在redis cluster进行resharding时,就是将keys从一个实例移动到另一个实例。`移动hash slot`代表`移动被hash到该slot的keys`。 + +`CLUSTER`命令拥有如下`subcommands`来操作redis cluster node中的`slot translation table`: +- `CLUSTER ADDSLOTS slot1 [slot2]...[slotN]` +- `CLUSTER DELSLOTS slot1 [slot2]...[slotN]` +- `CLUSTER ADDSLOTSRANGE start-slot1 end-slot1 [start-slot2 end-slot2]...[start-slotN end-slotN]` +- `CLUSTER DELSLOTSRANGE start-slot1 end-slot1 [start-slot2 end-slot2]...[start-slotN end-slotN]` +- `CLUSTER SETSLOT slot NODE node` +- `CLUSTER SETSLOT slot MIGRATING node` +- `CLUSTER SETSLOT slot IMPORTING node` + +在上述命令中,`ADDSLOTS, DELSLOTS, ADDSLOTSRANGE, DELSLOTSRANGE`四个命令用于`assign/remove slots to redis node`。(`Assigning a slot means to tell a given master node that it will be in charge of storing and serving content for the specified hash slot`) + +当hash slots被分配后,其将会通过gossip protocol在cluster的范围内传播该信息。 + +`ADDSLOTS/ADDSLOTSRANGE`命令通常在`新集群被从头创建,为每个master节点分配所有16384个hash slots的子集时`被使用。 + +`DELSLOTS/DELSLOTSRANGE`则主要在手动修改cluster configuration时被使用,通常其使用场景较少。 + +> `ADDSLOTS, DELSLOTS, ADDSLOTSRANGE, DELSLOTSRANGE`命令只修改slot归属,`不负责数据的迁移或删除`。 + +`SETSLOT`命令则用作则如下: +- `SETSLOT slot Node node`: assign a slot to a specific node ID +- `SETSLOT slot MIGRATING/IMPORTING node`:主要用于将hash slot从一个节点迁移到另一个节点 + - 当使用`MIGRATING`时,仅当key在node中存在时,该node将会接收所有针对该hash slot的查询;否则query将会通过ASK进行重定向 + - 当使用`IMPORTING`时,仅当request前缀ASKING时,该node会接收所有针对该hash slot的查询;如果client发送请求时并没有指定ASKING,那么将会返回`MOVED error`,将请求重定向到`owner of the hash slot` + +`slot migration`的示例如下,假设存在两个redis master nodes:`A和B`。如果想要将hash slot 8从A移动到B,那么可以发送如下命令: +- send B: `CLUSTER SETSLOT 8 IMPORTING A` +- send A: `CLUSTER SETSLOT 8 MIGRATING B`