• Redis之Redis Cluster


    【Redis Cluster简介】
    Redis Cluster(后面简写RC)是Redis作者自己提供的Redis集群化方案。RC是去中心化的,如图,集群由3个Redis节点组成,每个节点负责一部分数据,三个节点互联组成一个对等的集群,他们之间通过一种特殊的二进制协议交互集群信息。
    【槽位定位】
    RC将所有数据划分为16384个槽位,每个Redis节点负责一部分槽位,还是多对一的关系。但与Codis不同,RC将槽位信息存在每个节点中(如何同步映射关系呢?),当客户端来链接集群时,也会得到一份集群的槽位配置信息,所以客户端查找某个key时,可以直接定位到目标节点。这里可以对比一下RC与Codis在槽位划分以及key寻找Redis实例的实现思路上进行对比,然后想想两种实现思路上的差异。
    RC会默认对key值使用crc16算法进行hash,得到一个整数,而后用这个整数对16348进行取模得到具体地槽位。另外,RC也允许用户强制把某个key挂在特定的槽位上(在key字符串里嵌入tag标记)。
    【跳转】
    在槽位定位时说过,客户端那里会得到一份集群的槽位配置信息,但这里每个节点存储一份/客户端缓存一份整体上会造成不同步,所以客户端查询key时指定的节点不一定是准确的;另外客户端虽然有配置信息,但客户端行为不可控,也有可能故意发送错误的节点信息。所以此时,RC的处理策略是,向客户端发送一个特殊的跳转指令,携带目标操作的节点准确地址,告诉客户端去链接这个节点以获取数据。
    客户端获取到这个提示后,要立即纠正本地的槽位映射表,再继续操作。
    【迁移】
    RC提供了redis-trib可以让运维人员手动调整槽位的分配情况,通过各种原生的RC指令来实现。与Codis提供了人性化的UI操作界面和自动化平衡槽位工具相比,RC的策略就是提供最小可用工具,其它都交由社区完成。
    这一小节主要讨论迁移的流程以及迁移中客户端访问的应答处理情况。
    ----迁移流程----
    RC迁移时,迁移的单位是槽,一个槽一个槽地进行迁移,然后对迁移源与迁移目标槽做标记,前者标记为migrating,后者是importing状态。下图反映了迁移的整个过程:

    整体流程:redis-trib首先会在源节点和目标节点设置好中间过渡状态,然后一次性获取到源节点槽位的所有key列表(keysinslot指令可以部分获取),再挨个对key进行迁移。
    单key迁移流程:源节点对当前key执行dump指令,得到序列化的内容,然后以一个客户端的身份去访问目标节点,并以刚才序列化好的内容作为参数发送restore请求,目标节点将这个参数反序列化后存在自己的节点,并向"客户端"源节点返回OK,源节点此时将key和值删除,整个key的迁移结束。
    在这个过程中,源节点的主线程会阻塞,即发送restore-等到OK-删除key-删除key成功,整个过程是阻塞的。
    如果这个过程中发生了网络故障,整个槽的迁移中途打断,那么下次迁移工具重新连上时,这两个节点还是过渡状态,待下次迁移工具重新连上时,会提示用户继续迁移。
    最佳实践点:通过上面的描述,基本了解了RC迁移slot的过程,如果key的内容很大,而migrate指令是阻塞指令,会同时导致源节点和目标节点卡顿,影响集群的稳定性,所以在集群环境下,尽量避免产生很大的key。
    ----迁移过程中的客户端访问----

    在迁移过程中,老slot对应的key会分布在老的slot和新的slot中。客户端首先尝试访问老节点,如果对应的数据还在老节点中,那么可以正常处理。如果对应的数据不在老节点中,那么有两种可能,要么key不存在,要么key在新的节点里。旧节点不知道情况,所以会向客户端返回一个-ASK targetNodeAddr的重定向指令,客户端收到这个指令后,先去目标节点执行一个不带任何参数的ASKING指令,然后在目标节点再重新执行原先的操作指令。
    如果不使用这个机制,那么请求打到新节点时,这时slot-redis实例的路由算法会判定这个key不在新节点中,会向客户端返回一个-MOVED重定向指令告诉它去找源节点执行,从而形成重定向循环。
    从以上流程看出,这个指令会需要3个ttl才能完成,迁移是会影响服务效率的。
    【容错】
    RC可以为每个主节点设置若干个从节点,当主节点发生故障时,集群会自动将其中某个从节点提升为主节点。
    如果某个主节点没有从节点,那么发生故障时,集群将完全处于不可用状态。
    不过Redis也提供了一个参数cluster-require-full-coverage可以允许部分节点发生故障,其他节点还可以继续提供对外访问。
    【网络抖动】
    当网络抖动发生时,某个节点会失联一小会儿,然后很快又恢复正常。
    为了解决这个问题,RC提供了cluster-node-timeout选项,表示这个节点持续timeout失联时,才判定该节点出现故障,需要进行主从切换。
    cluster-slave-validity-factor可以作为上面timeout的倍数,进行从节点是否进行多次failover的设置。factor=0,就是失联了之后,不管多久都会去尝试夺权(failover),但是正数的时候,超过factor*timeout,就消停了,不夺权了。

    【PF可能下线与F确定下线】
    RC是去中心化的,所以一个节点认为某个节点失联了并不代表所有的节点都认为它失联了,所以集群还得经过一次协商的过程,只有当大多数节点都认定某个节点失联了,集群才认为该节点需要进行主从切换来容错。
    RC集群节点采用Gossip协议来广播自己的状态以及改变对整个集群的认知。比如一个节点发现某个节点失联了(PF),它会将这条信息向整个集群广播,其他节点都可以收到这个点的失联信息,如果收到了某个节点的失联数量已经达到了集群的大多数,就可以标记该失联节点为确定下线(F)的状态,然后向整个集群广播,强迫其它节点也接受该节点已经下线的事实,并立即对该失联节点进行主从切换。
    【槽位迁移感知】
    如果RC某个槽位正在迁移或者已经迁移完毕,那么客户端如何感知槽位的变化?
    前面提到RC有两个特殊的error指令,一个是MOVED,一个是ASKING。MOVED用于纠正槽位,ASKING是临时纠正槽位。注意asking被客户端收到之后,客户端不会刷新槽位关系映射表,因为这只是临时纠正该信息,不影响后续指令。
    ----重试2次----
    客户端查某个key,结果被MOVED到一个新的节点,然后新的节点刚好在迁移,又被发送了一个ASKING。
    ----重试多次----
    基于上面的认知,重试多次是可能的,基于此,Java和Python都设置了最大重试次数这个参数,当重试次数超过这个值时,客户端会向业务层抛出异常。
    【集群变更感知】
    服务器节点变更时,客户端应立即得到通知以实时刷新自己的节点关系表。
    1.目标节点挂掉
    客户端会抛出ConnectionError,紧接着随机挑选一个节点来重试,被重试的二节点通过MOVED指令告知被分配到的新的节点地址。
    2.运维手动修改集群信息,将主节点切换到别的节点,并将旧节点移出集群。这是在旧的主节点上的指令会收到ClusterDown的错误,告知当前节点所在集群不可用。此时客户端就会关闭所有连接,清空槽位映射关系表,然后向上层抛错。待下一条指令过来时,就会重新尝试初始化节点信息。
    【参考】
    《Redis深度历险 核心原理与应用实践》

  • 相关阅读:
    以太坊投票智能合约案例
    以太坊公开拍卖智能合约案例
    智能合约入门
    [elk]es增删改查最佳实战
    [elk]es增删改查最佳实战
    [elk]es增删改查最佳实战
    使nfs同步生效
    mysql建立ssl安全连接的配置
    mysql建立ssl安全连接的配置
    mysql建立ssl安全连接的配置
  • 原文地址:https://www.cnblogs.com/bruceChan0018/p/15758531.html
Copyright © 2020-2023  润新知