diff --git a/中间件/redis/redis.md b/中间件/redis/redis.md index f90fc36..5997b28 100644 --- a/中间件/redis/redis.md +++ b/中间件/redis/redis.md @@ -216,6 +216,11 @@ - [Redirection and Resharding](#redirection-and-resharding) - [MOVED Redirection](#moved-redirection) - [Live reconfiguration](#live-reconfiguration) + - [ADDSLOTS/DELSLOTS](#addslotsdelslots) + - [MIGRATING/IMPORTING](#migratingimporting) + - [MIGRATE](#migrate) + - [`CLUSTER GETKEYSINSLOT`](#cluster-getkeysinslot) + - [MIGRATE](#migrate-1) # redis @@ -3422,6 +3427,7 @@ client不必须,但是应该记住`hash slot 3999被127.0.0.1:6381管理`。 当集群处于稳定状态下时,最终所有客户端都会获取到`map of hash slots`,确保cluster效率更高,client无需重定向就能查询到正确的nodes。 #### Live reconfiguration +##### ADDSLOTS/DELSLOTS 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 @@ -3448,13 +3454,54 @@ Redis Cluster支持在运行时动态添加、移除nodes的能力。对redis cl > `ADDSLOTS, DELSLOTS, ADDSLOTSRANGE, DELSLOTSRANGE`命令只修改slot归属,`不负责数据的迁移或删除`。 -`SETSLOT`命令则用作则如下: - `SETSLOT slot Node node`: assign a slot to a specific node ID + +##### MIGRATING/IMPORTING +除了通过ADDSLOTS/DELSLOTS改变slots的归属外,slot还可以被设置为两个特殊的状态`MIGRATING`, `IMPORTING`。上述这两个特殊状态用于`migrate a hash slot from one node to another`。(由于ADDSLOTS/DELSLOTS只负责修改slot归属,并不负责数据迁移,故而在数据迁移时需要通过`MIGRATING/IMPORTING`来支持) + +`SETSLOT`命令则用作则如下: - `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被标记为`MIGRATING`时,代表node为迁移的`源节点`。当该节点接收到关于该hash slot的请求时: + - 如果请求中的key存在,则服务该请求 + - 如果请求中的key不存在,则可能已经迁移到目标节点中,此时会使用`ASK`重定向,将请求转发到迁移的`目标节点` + - 当slot被设置为`IMPORTING`时,代表node为迁移的`目标节点`。该节点只在`request is preceded by an ASKING command`时,才会服务该请求 + - 如果client在发送针对slot的请求前,没有先发送`ASKING`命令,那么当前请求将会通过`MOVED` redirection error被转发给`source node`(此时,数据迁移尚未完成,迁移的源节点仍然被视为`owner of the slot`) + +按照上述描述,slot迁移的示例如下所示: +- 假设拥有两个master nodes,分别为`A, B`,如果希望将`slot 8`从node A移动到`node B`,那么发送的命令如下所示: + - 向node B发送`CLUSTER SETSLOT 8 IMPORTING A` + - 该命令将node B标记为了目标节点,并指定源节点为A + - 向node A发送`CLUSTER SETSLOT 8 MIGRATING B` + - 该命令将目标A标记为了源节点,并指明了目标节点B + +此时,节点A作为slot迁移的源节点,在迁移过程中仍然被cluster看作是`owner of hash slot`。故而,当其他节点接收到关于`迁移中slot`的请求时,仍然将其重定向到node A,此时,A对于请求的处理如下: +- 如果请求的key仍在node A中存在,那么node A处理该请求 +- 如果请求的key不再node A中,那么其会通过`ASK`将请求重定向到B,此时客户端首先向node B发送`ASKING`,然后再重新发送请求 + +> 在节点迁移过程中,不仅允许对key执行读操作,也允许对其执行写操作。例如,若key之前在集群中不存在,并且被hash到`slot 8`,此时`slot 8`正在迁移。故而,client针对key的创建操作会先被`MOVED error`重定向到源节点`node A`,`node A`中并没有该key,故而会被`ASK`重定向到目标节点`node B`。此时,`node B`会处理client的key创建请求。 +> +> `故而,在slot迁移的过程中,针对slot中key的创建,统一在目标节点处写入,创建操作并不由源节点处理。` + +##### MIGRATE +可以通过在`redis-cli`中执行如下命令来将slot中的keys来进行迁移 + +###### `CLUSTER GETKEYSINSLOT` +```redis-cli +CLUSTER GETKEYSINSLOT slot count +``` +该命令将会返回指定hash slot中`count`数量的keys。对于返回的keys,可以通过`MIGRATE`命令来进行迁移,从A到B的迁移是原子的(来源和目标instance都会会locked)。 + +###### MIGRATE +```redis-cli +MIGRATE target_host target_port "" target_database id timeout KEYS key1 key2 ... +``` +上述命令将会连接到目标节点,发送`serialized version of the key`,并且一旦接收到`OK` code之后,源节点中key将会被删除。 + +> 故而,在任何时刻,对于外部client而言key要么存在于A中,要么存在于B中。 + +在redis cluster中,无需将database指定为`0`之外的值,此处支持`database`选项主要是为了redis cluster外的其他场景。`MIGRATE`命令经过优化,即使在移动`long lists`之类的复杂key也能保持较快的速度。 + +当迁移过程结束之后,`SETSLOT NODE `命令将会被发送给涉及迁移的两个节点,从而将slots重新设置回其正常状态(之前状态为MIGRATING/IMPORTING)。通常情况下,该命令也会被发送给其他所有节点,从而避免`new configuration`在集群间的传播耗费太长时间。 + -`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`