10.7、集群运维

集群运维

Redis集群由于自身的分布式特性,相比单机场景在开发和运维方面存在一些差异。本节我们关注于常见问题进行分析定位。

  1. 集群完整性

    为了保证集群完整性,默认情况下当集群16384个槽任何一个没有只拍到节点时整个集群不可用。执行任何键命令返回(error)CLUSTERDOWN Hash slot not served错误。这是对集群完整性的一种保护措施,保证所有的槽都指派给在线的节点。但是当持有槽的主节点下线时,从故障发现到自动完成转移期间整个集群是不可用状态,对于大多数业务无法容忍这种情况,因此建议将参数cluster-require-full-coverage配置为no,当主节点故障时只影响它负责槽的相关命令执行,不会影响其他主节点的可用性。

  2. 带宽消耗

    集群内Gossip消息通信本身会消耗带宽,官方建议集群最大规模在1000以内,也是出于对消息通信成本的考虑,因此单集群不适合部署超大规模的节点。在之前节点通信小节介绍到,集群内所有节点通过ping/pong消息彼此交换信息,节点间消息通信对带宽的消耗体现在以下几个方面:

    • 消息发送频率:跟cluster-node-timeout密切相关,当节点发现与其他节点最后通信时间超过cluster-node-timeout/2时会直接发送pnig消息。

    • 消息数据量:每个消息主要的数据占用包含:slots槽数组(2KB空间)和整个集群1/10的状态数据(10个节点状态数据约1KB)。

    • 节点部署的机器规模:机器带宽的上线是固定的,因此相同规模的集群分布的机器越多每台机器划分的节点越均匀,则集群内整体的可用带宽越高。

    集群带宽消耗主要分为:读写命令消耗+Gossip消息消耗。因此搭建Redis集群时需要数据业务数据估摸和消息通信成本做出合理规划:

    • 在满足业务需要的情况下尽量避免大集群。同一个系统可以针对不同业务场景拆分使用多套集群。这样每个集群既满足伸缩性和故障转移要求,还可以规避大规模集群的弊端。

    • 适度提高cluster-node-timeout降低消息发送频率,同时cluster-node-timeout还影响故障转移的速度,因此需要根据自身业务场景兼顾二者的平衡。

    • 如果条件允许集群尽量均匀部署在更多机器上。避免集中部署。

  3. Pub/Sub广播问题

    Redis在2.0版本提供了Pub/Sub(发布/订阅)功能,用于针对频道实现消息的发布和订阅。但是在集群模式下内部实现对所有的publish命令都会向所有的节点进行广播,造成每条publish数据都会在集群内所有节点传播一次,加重带宽负担。

    针对集群模式下publish问题,需要引起开发人员注意,当频繁应用Pub/Sub功能时应该避免在大量节点的集群内使用,否则会严重消耗集群内网络带宽。针对这种情况建议使用sentinel结构专门用于Pub/Sub功能,从而规避这一问题。

  4. 集群倾斜

    集群倾斜指不同节点之间数据量和请求量出现明显差异,这种情况将加大复杂均衡和开发运维的难度。因此需要理解哪些原因会造成集群倾斜,从而避免这一问题。

    1. 数据倾斜

      数据倾斜主要分为以下几种:

      • 节点和槽分配严重不均。

      • 不同槽对应键数量差异过大。

      • 集合对象包含大量元素。

      • 内存相关配置不一致。

    2. 请求倾斜

      集群内特定节点请求量/流量过大将导致节点之间负载不均,影响集群均衡和运维成本。常出现在热点键场景,当键命令消耗较低时如小对象的get、set、incr等,即使请求量差异较大一般也不会产生负载严重不均。但是当热点键对应高算法复杂度的命令或者是大对象操作如hgetall、smembers等,会导致对应节点负载过高的情况。避免方式如下:

      • 合理设计键,热点大集合对象做拆分或使用hmget替代hgetall避免整体读取。

      • 不要使用热键作为hash_tag,避免映射到同一槽。

      • 对于一致性要求不高的场景,客户端可使用本地缓存减少热键调用。

  5. 集群读写分离

    1. 只读连接

      集群模式下从节点不接受任何读写请求,发送过来的键命令会重定向到负责槽的主节点上(其中包括它的主节点)。当需要使用从节点分担主节点读压力时,可以使用readonly命令打开客户端连接只读状态。之前的复制配置slave-read-only在集群模式下无效。当开启只读状态时,从节点接收读命令处理流程为:如果对应的槽属于自己正在复制的主节点则直接执行读命令,否则返回重定向信息。

      readonly命令是连接级别生效,因此每次新建连接时都需要执行readonly开启只读状态,执行readwrite命令可以关闭连接只读状态。

    2. 读写分离

      集群模式下的读写分离,同样会遇到:数据延迟、读到过期数据、从节点故障等问题。针对从节点故障问题,客户端需要维护可用节点列表,集群提供了cluster salves {nodeId}命令,返回nodeId对应主节点下所有从节点信息,数据格式同cluster nodes。

      开发提示:集群模式下读写分离设计对客户端修改如下:

      • 维护每个主节点可用从节点列表。

      • 针对读命令维护请求节点路由。

      • 从节点新建连接开启readonly状态。

      集群模式下读写分离成本比较高,可以直接扩展主节点数量提高集群性能,一般不建议集群模式下做读写分离。

      集群读写分离有事用于特殊业务场景,如:

      • 利用复制的最终一致性使用多个从节点做跨机房部署降低读命令网络延迟。

      • 主节点故障转移时间过长,业务端把读请求路由给从节点保证读操作可用。

      以上场景也可以用在不同机房独立部署Redis集群解决,通过客户端多写来解决,读命令量直接请求到最近机房的Redis集群,或者当一个集群节点故障时客户端转向另一个集群。

  6. 手动故障转移

    Redis集群提供了手动故障转移功能:指定从节点发起转移流程,主从节点角色进行切换,从节点变为新的主节点对外提供服务,旧的主节点变为它的从节点。

    从节点上执行cluster failover命令发起转移流程,默认情况下转移期间客户端请求会有短暂的阻塞,但不会丢失数据,流程如下:

    • 从节点通知主节点停止处理所有客户端请求。

    • 主节点发送对应从节点延迟复制的数据。

    • 从节点接收处理复制延迟的数据,直到主从复制偏移量一致为止,保证复制数据不丢失。

    • 旧主节点接受到消息后更新自身配置变为从节点,接触所有客户端请求阻塞,这些请求会被重定向到新主节点上执行。

    • 旧主节点变为从节点后,向新的主节点发起全量复制流程。

    运维提示:主从节点转移后,新的从节点由于之前没有缓存主节点信息无法使用部分复制功能,所以会发起全量复制,当节点包含大量数据时会严重消耗CPU和网络资源,线上不要频繁操作。

    手动故障转移的应用场景主要如下:

    1)主节点转移:运维Redis集群过程中京城遇到调整节点部署的问题,如节点所在的老机器替换到新机器等。由于从节点默认不响应请求可以安全下线关闭,但直接下线主节点会导致故障自动转移期间主节点无法对外提供服务,影响线上业务的稳定性。这时可以使用手动故障转移,把要下线的主节点安全的替换为从节点后,再做下线操作。

    2)强制故障转移:当自动故障转移失败时,只要故障的主节点有存活的从节点就可以通过手动转移故障强制让从节点替换故障的主节点,保证集群的可用性。自动故障转移失败的场景有:

    • 主节点和它的所有从节点同时故障。这个问题需要通过调整节点机器部署拓扑做规避,保证主从节点不在同一机器/机架上。除非机房内大面积故障,否则两台机器/机架同时故障概率很低。

    • 所有从节点与主节点复制断线时间超过cluster-slave-validity-factor * cluster-node-timeout + repl-ping-slave-period,导致从节点被判定为没有故障转移资格,手动故障转移从节点不做中断超时检查。

    • 由于网络不稳定等问题,故障发现或故障选举时间无法在cluster-node-timeout*2内完成,流程会不断重试,最终从节点复制中断时间超时,失去故障转移资格无法完成转移。

    • 集群内超过一半以上的主节点同时故障。

    根据以上情况,cluster failover命令提供了两个参数force/takover提供支持:

    • cluster failover force——用于当主节点宕机且无法自动完成故障转移情况。从节点接到cluster failover force请求时,从节点直接发起选举,不再跟主节点确认复制偏移量(从节点复制延迟的数据会丢失),当从节点选举成功后替换为新的主节点并广播集群配置。

    • cluster failover takeover——用于集群内超过一半以上主节点故障的场景,因为从节点无法收到半数以上主节点投票,所以无法完成选举过程。可以执行cluster failover takover强制转移,接到命令的从节点不再进行选举流程而是直接更新本地配置纪元并替换主节点。takeover故障转移由于没有通过领导者选举发起故障转移,会导致配置纪元存在冲突的可能。当冲突发生时,集群会以nodeId字典序更大的一方配置为准。因此要小心集群分区后,手动执行takeover导致的集群冲突问题。

    在集群可以自动完成故障转移的情况下,不要使用cluster failover takeover强制干扰集群选举机制,该操作主要用于半数以上主节点故障时采取的强制措施,请慎用。

    运维提示:手动故障转移时,在满足当前需求的情况下建议优先级:cluster failover > cluster failover force > cluster failover takeover.

  7. 数据迁移

    应用Redis集群时,常需要把单机Redis数据迁移到集群环境。redis-trib.rb工具提供了导入功能,用于护具从单机向集群环境迁移的场景,命令如下:

    redis-trib.rb import host:port --from  --copy --replace
    

    redis-trib.rb import命令内部采用批量scan和migrate的方式迁移数据。这种迁移方式存在以下缺点:

    • 迁移只能从单机节点向集群环境导入数据。

    • 不支持在线迁移数据,迁移数据时应用方必须停写,无法平滑迁移数据。

    • 迁移过程中途如果出现超时等错误,不支持断点续传只能重新全量导入。

    • 使用单线程进行数据迁移,大量数据迁移速度过慢。

    正因为这些问题,社区开源了很多迁移工具,这里推荐一款唯品会开发的redis-migrate-tool,该工具可满足大多数Redis迁移需求,特点如下:

    • 支持单机、Twemproxy、Redis cluster、RDB/AOF等多种类型的数据迁移。

    • 工具模拟成从节点基于复制流迁移数据,从而支持在线迁移数据, 业务方不需要停写。

    • 曹勇多线程加速数据迁移过程且提供数据校验和查看迁移状态等功能。

你可能感兴趣的:(10.7、集群运维)