Redis-7-集群练习

目录

1.前言

2.扩容集群

3.收缩集群

4.客户端路由

5.ASK与MOVED区别

6.对应的指令详解

6.1 cluster meet

6.2 cluster setslot

6.2.1 MIGRATING子命令

6.2.2 IMPORTING子命令

6.2.3 STABLE

6.3.4 NODE

6.3 cluster getkeysinslot

6.4 migrate

6.5 cluster forget

7.参考资料



1.前言

通过上一章节,我们知道了Redis Cluster采用的是虚拟哈希槽分区,一共分为0-16383个槽位,数据分别落在这些不同的槽位上;

假如,目前集群有N台服务器,这N台服务器加起来维护着0-16383个槽位,每一台机器负责维护一部分槽以及槽所映射的键值数据,槽是Redis集群管理数据的基本单位,集群伸缩就是槽和数据在节点之间的移动:

①当我加1台机器,该集群变成(N+1)台机器,此刻                                                       需要把一些槽位移动到这个新增的机器上;

②当我减1台机器,该集群变成(N-1)台机器,此刻需要把该机器上的槽位移动到其他机器上;

2.扩容集群

当一个新节点Master4加入现有集群后,我们需要把Master1、Master2、Master3上的一些槽位进行迁移,确保迁移后每个节点负责相似数量的槽,从而保证这些节点的数据均匀,为此新节点Master4指定槽的迁移计划,整个迁移计划可以分为2部分:槽位迁移、子节点列表更新,具体步骤如下:

第一步:启动Master4节点,记为M4;

第二步:使用cluster meet命令,让M4节点加入到集群中。新节点刚开始都是主节点状态,由于没有负责的槽,所以不能接受任何读写操作,后续需要为其迁移槽和填充数据;

第三步:对M4节点发送cluster setslot {slot} importing {sourceNodeId}命令,让目标节点M4准备导入槽的数据;

第四步:对源节点Master1、Master2、Master3节点发送cluster setslot {slot} migrating {targetNodeId}命令,让源节点准备迁出槽的数据;

第五步:源节点Master1、Master2、Master3执行cluster getkeysinslot {slot} {count}命令,获取count个属于槽{slot} 的键;

第六步:在源节点Master1、Master2、Master3上执行migrate {targetNodeIp} " " 0 {timeout} keys {key...}命令,把获取的key通过pipeline机制批量迁移到目标节点;

第七步:重复执行第5-6步,直到槽下所有的键值数据迁移到目标节点;

第八步:向集群内所有主节点发送cluster setslot {slot} node {targetNodeId}命令,通知槽分配给目标节点了,往后从该节点那对应槽位的数据,同时为了保证槽节点映射变更及时传播,需要遍历发送给所有主节点,以便更新被迁移的槽执行新节点;

3.收缩集群

收缩节点就是将某个节点下线,整个流程分为2部分:该节点槽位转移到其他节点、更新节点列表把该节点关闭,具体步骤如下:

槽位转移到其他节点,与《扩容集群》一致,区别在于当迁移完槽后,还需要通知集群内所有节点忘记下线的节点,即Redis集群使用cluster forget {downNodeId}命令来讲指定的节点加入到禁用列表中,在禁用列表内的节点不再发送Gossip消息;

4.客户端路由

在集群模式下,Redis节点接收任何键相关命令时首先计算键对应的槽,在根据槽找出所对应的节点,如果节点是自身,则处理键命令;否则回复MOVED重定向错误,通知客户端请求正确的节点。这个过程称为MOVED重定向。

Redis计算槽时并非只简单的计算键值内容,当键值内容包括大括号时,则只计算括号内的内容。比如说,key 为 user:{10000}:books时,计算哈希值只计算10000。

由于请求重定向会增加IO开销,必须借助Smart集群客户端。Smart客户端通过在内部维护slot到Redis节点的映射关系,本地就可以实现键到节点的查找,从而保证IO效率的最大化,而MOVED重定向负责协助客户端更新映射关系;

5.ASK与MOVED区别

ASK和MOVED虽然都是对客户端的重定向控制,但是有着本质区别:

ASK重定向说明集群正在进行slot数据迁移,客户端无法知道什么时候迁移完成,因此只能是临时性的重定向,客户端不会更新 slot到Redis节点的映射缓存

MOVED重定向说明键对应的槽已经明确指定到新的节点,因此需要更新slot到Redis节点的映射缓存

6.对应的指令详解

6.1 cluster meet

CLUSTER MEET命令被用来连接不同的、开启集群支持的Redis节点,以进入工作集群;(通俗来讲就是新节点加入已经搭建好的集群

由于每个节点默认都是相互不信任的,且被认为是未知的节点,这是因为即便某一天人为失误配置IP错误,也不会把N个不同集群节点混成一个集群,因为节点与节点之间默认是互不信任与未知的;

为了使特定节点加入到其他节点组成的Redis Cluster节点列表中,这里只有2种方法:

①系统管理员发送一个CLUSTER MEET命令强制一个节点去会面另一个节点;

②一个已知的节点发送一个保存在gossip部分的节点列表,包含着未知的节点。如果接收的节点已经将发送节点信任为已知节点,它会处理gossip部分并且发送一个握手消息给未知的节点。

思考:Redis Cluster需要形成一个完整的网络,即每个节点与其他任何一个节点都会建立连接,那是不是意味着新节点要对其他所有节点都发送一次CLUSTER MEET命令呢?

答:不需要,假如A-B-C-D之间已经建立了节点链,当新节点E通过CLUSTER MEET命令与D建立连接后,相当于暂时存在A-B-C-D、D-E这2个节点链,然后由于在心跳包中会交换gossip信息,因此A-E、B-E、C-E将会自动创建节点链;

6.2 cluster setslot

该命令、及其子命令可以用来启动、结束一个群集重新分配哈希槽的操作,操作期间,会把源节点对应槽设置为迁移中状态,目标节点设置为导入中状态,子命令可以修改接受节点中哈希槽的状态,具体如下:

①MIGRATING:将一个哈希槽设置为migrating 状态

②IMPORTING:将一个哈希槽设置为importing 状态

③STABLE:从哈希槽中清除导入和迁移状态

④NODE:将一个哈希槽绑定到另一个不同的节点

6.2.1 MIGRATING子命令

CLUSTER SETSLOT  MIGRATING 

该子命令将一个槽设置为migrating状态.为了可以将一个哈希槽设置成这种状态,收到命令的节点必须是该哈希槽的所有者,否则报错,当一个哈希槽被设置为migrating状态,节点将会有如下操作:

①客户端发来的操作指令中的key如果存在,则命令正常执行;

②客户端发来的操作指令中的key如果不存在,则接收命令的节点将发出一个重定向ASK,让客户端紧在destination-node重试该查询。在这种情况下,客户端不应该将该哈希槽更新为节点映射;

③如果客户端发来的命令中包含多个keys,如果都不存在,处理方式同2;如果都存在,处理方式同1;如果只是部分存在,针对即将完成迁移至目标节点的keys按序返回TRYAGAIN错误,以便批量keys命令可以执行;

6.2.2 IMPORTING子命令

CLUSTER SETSLOT IMPORTING

该子命令将keys从指定源节点导入目标节点,该命令仅能在目标节点生效,当一个槽被设置为导入中状态时,该节点的变动情况如下:

客户端发过来的指令中,凡是涉及该哈希槽的命令均被拒绝,并产生一个MOVED重定向,但是如果客户端命令后面紧跟着一个ASKING命令时,目标节点就必须执行,这是因为:

第一步:客户端往源节点发送指令,源节点在执行指令时,发现key不存在了,然后源节点给客户端返回一个ASK指令,或者,客户端直接给目标节点发送指令,目标节点给客户端返回一个MOVED指令,然后客户端收到MOVED指令后去访问源节点,然后源节点再给客户端返回一个ASK指令;

第二步:客户端收到这个ASK指令后,重新发指令发往目标节点,然后紧跟着发送一个ASKING指令;

第三步:当目标节点收到ASKING指令后,这才知道该key已经从源节点移动到我这目标节点了,我不能再回复MOVED指令了,否则客户端-MOVED-源节点-ASK-客户端-目标节点-MOVED-源节点....形成死循环了,看来,我不得不执行该命令了,因此,源节点已不存在的keys或者已经迁移至目标节点的keys的命令,都在目标节点执行,说明如下:

新的keys总是在目标节点创建。在哈希槽的迁移中,我们只迁移keys不会创建keys;

涉及已经迁移的keys的命令都会被目的节点处理,目的节点会是新的哈希槽的所有者,以保证一致性;

③如果没有ASKING,则该命令是普通指令,ASKING保证哈希槽映射关系错误的客户端不会在目的节点继续其他操作,例如新建key,毕竟新建key的操作应该在目标节点操作,而不是源节点;

6.2.3 STABLE

CLUSTER SETSLOT STABLE

该子命令仅用于清理槽中迁移中/导入中的状态。它主要用于修复群集在使用redis-trip fix命令后,卡在一个错误状态的场景, 一般情况下,使用SETSLOT... NODE...迁移完成时,这两种状态会被自动清理

6.3.4 NODE

CLUSTER SETSLOT NODE

该子命令使用最复杂,它后接指定节点的哈希槽,该命令仅在特定情况下有效,且不同的槽状态会有不同的效果,前提条件和对应的效果如下:

如果接受命令的节点是当前操作哈希槽的所有者但是该命令的操作结果是将操作的槽分配到另一个节点,因此,要操作的哈希槽中还有keys时,该命令会返回错误;

如果槽是migrating状态,当该槽被分配至其他节点时,migrating状态被清除;

如果槽在接收命令的节点上是importing状态,该命令将槽分配给这个节点(当进行重哈希时,最终结果哈希槽从一个节点迁移至目的节点)并做如下操作:

首先,状态importing被清除;

其次,如果该节点的配置epoch不是群集中最大的,它将生成一个新的配置epoch。这样,在经历过故障转移或者槽迁移的群集中,能够拿到新的哈希槽的所有权;

6.3 cluster getkeysinslot

CLUSTER GETKEYSINSLOT slot count

本命令返回存储在接受节点的指定hash slot里面的key的列表,key的最大数量通过count参数指定,所以这个API可以用作keys的批处理;

这个命令的主要是用于rehash期间slot从一个节点移动到另外一个节点;

6.4 migrate

MIGRATE host port key destination-db timeout [COPY] [REPLACE]

将key原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功,key保证会出现在目标实例上,而当前实例上的key会被删除

这个命令是一个原子操作,它在执行的时候会阻塞进行迁移的两个实例,直到以下任意结果发生:迁移成功,迁移失败,等到超时;

命令的内部实现是这样的:它在当前实例对给定key执行DUMP 命令 ,将它序列化,然后传送到目标实例,目标实例再使用RESTORE 对数据进行反序列化,并将反序列化所得的数据添加到数据库中;当前实例就像目标实例的客户端那样,只要看到RESTORE命令返回OK,它就会调用DEL删除自己数据库上的key;

timeout以毫秒为单位,指定当前实例与目标实例进行沟通的最大间隔时间。这说明操作并不一定要在timeout毫秒内完成,只是说数据传送的时间不能超过这个timeout数;

MIGRATE命令需要在给定的时间规定内完成IO操作。如果在传送数据时发生IO错误,或者达到了超时时间,那么命令会停止执行,并返回一个特殊的IOERR错误,当IOERR出现时,有以下2种可能:

①key可能存在于两个实例;

②key可能只存在于当前实例;

唯一不可能发生的情况就是丢失key ,因此,如果一个客户端执行MIGRATE命令,且不幸遇上IOERR错误,那么这个客户端唯一要做的就是检查自己数据库上的key是否已经被正确地删除。

如果有其他错误发生,那么MIGRATE保证key只会出现在当前实例中;

6.5 cluster forget

CLUSTER FORGET node-id

该命令可以从收到命令的Redis群集节点的节点信息列表中移除指定ID的节点;

该命令不是将待删除节点的信息简单从内部配置中简单删除,它同时实现了禁止列表功能:不允许已删除的节点再次被添加进来,否则已删除节点会因为处理其他节点心跳包中的gossip section时被再次添加,这段话怎么理解呢,举个例子:

  1. B-C-D,然后从C中删除D,删除成功后,A-B继续往C发送心跳包gossip section,然后A-B的心跳包又把D添加到了C的节点列表中,因此,命令CLUSTER FORGET为每个节点实现了包含超时时间的禁止列表;

因此,在实际情况下,命令执行过程是:

①从收到命令节点的节点信息列表中删除待删除节点的节点信息;

②已删除的节点的节点ID被加入禁止列表,保留1分钟;

③收到命令的节点,在处理从其他节点发送过来的gossip sections会跳过所有在禁止列表中的节点;

7.参考资料

Redis Cluster 的数据分片机制:https://cloud.tencent.com/developer/article/1437316

腾讯云:https://cloud.tencent.com/developer/section/1374001

Redis中文官方网站:http://www.redis.cn/

2W字详解Redis 6.0 集群环境搭建实践:https://mp.weixin.qq.com/s/6q_NaQaM2wgc1bgE5cpx0g

你可能感兴趣的:(Redis,Redis,Cluster,redis)