rabbitmq基础9——流控、镜像队列、网络分区

2023-11-08

文章目录

一、流控

  • 前面我们在讲解存储机制时,提到过流量控制。当消息积压时,消息会进入到队列深处,消费消息会使服务器性能大大降低。而内存告警和磁盘告警就是通过设置阈值来预防此情形,当达到阈值后,阻塞集群中所有的Connection,直到对应项恢复正常,属于全局性的流量控制 (Global Flow Control)。而这里将要提到的流控是针对连接Connection来的(Per-Connection Flow Control或者Internal Flow Control)。
  • 流控作用:
    • 流控机制是用来避免消息的发送速率过快而导致服务器难以支撑的情形,从而保障服务器资源在安全范围内,提高业务的稳定性。

1.1 流控机制

  • 流控是对什么进行控制?

    • 是对进程邮箱的阈值进行控制。
  • rabbitmq进程邮箱:

    • 进程通信方式有四种,分别为主从式、会话式、消息传递(邮箱机制)、共享存储区。而Erlang 进程之间并不共享内存 (binary 类型的除外),而是通过消息传递来通信,每个进程都有自己的进程邮箱(mailbox)。
    • 默认情况下,Erlang并没有对进程邮箱的大小进行限制,所以当有大量消息持续发往某个进程时,会导致该进程邮箱过大,最终内存溢出而崩溃。
    • 在rabbitmq中,如果生产者持续高速发送,而消费者消费速度较低时,如果没有流控,很快就会使内部进程邮箱的大小达到内存阈值。
  • 流控机制是什么?

    • rabbitmq使用了一种基于信用证算法(credit-based algorithm)的流控机制,来限制发送消息的速率来解决进程邮箱大小达到内存阈值而导致服务器崩溃问题。
    • 通过监控各个进程的进程邮箱,当某个进程负载过高而来不及处理消息时,这个进程的进程邮箱就会开始堆积消息。
    • 当堆积到一定量时,就会阻塞而不接收上游的新消息。从而慢慢地,上游进程的进程邮箱也会开始堆积消息。当堆积到一定量时也会阻塞而停止接收上游的消息,最后就会使负责网络数据包接收的进程阻塞而暂停接收新的数据。

1.2 流控原理

  • 流控原理流程:
    • 进程XXX——> 进程A——> 进程B——> 进程C—— 进程…,每个进程中都有一对关于收发消息的credit值。
    • 拿进程B来看,有两个参数:
    • {{credit_from,C},value]参数,表示能发送多少条消息给进程C,每发送一条消息该值减 1,当为 0 时,进程 B 不再往进程 C 发送消息也不再接收进程 A 的消息。
    • [{credit_to,A},value}参数,表示再接收多少条消息就向进程A 发送增加credit值的通知,进程 A 接收到该通知后就增加{{credit_from,B),value] 所对应的值,这样进程 A 就能持续发送消息。
      • 当上游发送速率高于下游接收速率时,credit值就会被逐渐耗光,此时进程被阻塞,阻塞情况会一直传递到最上游。
      • 当上游进程收到来自下游进程的增加 credit 值的通知时,若此时上游进程处于阻塞状态则解除阻塞,开始按收更上游进程的消息,一个一个传导最终能够解除最上游的阻塞状态。
      • 综上分析可知,基于信用证的流控机制最终将消息发送进程的发送速率限制在消息处理进程的处理能力范围之内。

在这里插入图片描述

1.3 流控状态显示

  • 当一个连接(Connection)触发流控时会处于“flow”的状态,代表此Connection状态每秒在 blocked 和 unblocked 之间来回切换数次。以此可以将消息发送的速率控制在服务器能够支撑的范围之内。web页面可以查看,也可以通过 rabbitmactl list_connections 命令查看。

在这里插入图片描述

1.4 流控对象

  • 流控机制对象:

    • 连接(Connection)
    • 信道 (Channel)
    • 队列(Queue)
  • 如下图,从Connection进程——> Channel进程——> Queue进程——> 消息持久化存储进程,是一条消息从接收到存储的一个必需的流控连,对于处于整个流控链中的任意进程,只要该进程阻塞,上游的进程必定全部被阻塞。

在这里插入图片描述

  • 主要进程:

    • rabbit_reader进程:连接的处理进程,负责接收、解析 AMQP 协议数据包等。
    • rabbit_channel进程:信道的处理进程,负责处理AMQP协议的各种方法、进行路由解析等。
    • rabbit_amqqueue_process进程:队列的处理进程,负责实现队列的所有逻辑。
    • rabbit_msg_store进程:负责实现消息的持久化。
  • 各进程状态情形分析:

    • 当某个Connection处于 flow 状态时,但这个 Connection 中没有一个 Channel 处于 flow 状态,代表这个Connection中有一个或者多个 Channel 出现了性能瓶颈。
      • 存在情形:某些 Channel进程的运作(比如处理路中逻辑) 导致服务器 CPU 的负载过高,尤其是在发送大量较小的非持久化消息时最容易发生。
    • 当某个 Connection处于flow 状态,这个Connection 中也有若干个 Channel 处于 flow状态,但没有任何一个对应的队列处于 flow 状态时,这就意味着有一个或者多个队列出现了性能瓶颈。
      • 存在情形:消息存入队列时导致服务器CPU 负载过高;持久化消息入盘导致服务器 I/O 负载过高,尤其是在发送大量较小的持久化消息时最容易发生。
    • 当某个 Connection处于 flow 状态,这个 Connection 中的若干个 Channel 处于 flow状态,并且也有若干个对应的队列处于 flow 状态时,这就意味着在消息持久化时出现了性能瓶颈。
      • 存在情形:持久化消息入盘导致服务器 I/O 负载过高,尤其是在发送大量较大的持久化消息时最容易发生。

1.5 性能提升

  • 一般情况下,向一个队列里推送消息时,往往会在rabbit_amqqueue_process中(即队列进程中) 产生性能瓶颈。
  • 提升队列性能方式
    • 第一种,若Erlang版本在18.x以上,可以开启HiPE 功能,可以提高 30%~40%的性能。
    • 第二种,代码层面提升,将单个rabbit_amqqueue_process替换成多个rabbit_amqqueue_process。这里并不是使用多个队列,而是将交换器、队列、绑定关系、生产和消费的方法全部进行封装,这样对于应用来说好是在操作一个(逻辑) 队列。至于怎么封装的,纯运维就不用去了解了,开发就自行百度测试。

在这里插入图片描述

二、镜像队列

  • 镜像队列在解决什么?
    • 镜像队列 (Mirror Queue) 机制,可以将队列镜像到集群中的其他Broker节点之上。当集群中的一个节点失效了,队列能自动地切换到镜像中的另一个节点上,以此可以保证服务的可用性,而不是节点实现其上的队列不可用。

2.1 机制原理

  • 一般情况下,给每一个配置镜像的队列,即镜像队列都包含一个主节点(master) 和若千个从节点 (slave)。如下图,给qingjun_queue队列配置镜像包含了一个主节点和两个从节点。这里要注意镜像的主从节点和rabbitmq服务主从节点的区别。
  • 实现原理:
    • 镜像队列的slave节点会准确地按照镜像队列的master节点执行命令的顺序进行动作,所以镜像队列的master节点和slave节点数据是相同的,维护状态也应该是相同的。
    • 当镜像队列的master节点失效,"资历最老"的镜像队列slave1就会被提升为新的master。选主机制是根据镜像队列save节点加入时间顺序来的,时间最长的slave 即为“资历最老”。
    • 发送到镜像队列的所有消息会被同时发往 master 和所有的 slave 上,如果此时 master 挂掉了,消息还会在 slave 上,这样 slave提升为 master 的时候消息也不会丢失。除发送消息 (Basic.Publish) 外的所有动作都只会向 master 发送,然后再由 master 将命令执行的结果广播给各个 slave。
  • 注意事项:
    1. 若消费者与slave建立连接并进行订阅消费,其实质上都是从 master 上获取消息,只不过看似是从 slave 上消费而已。
    2. 比如消费者与 slave 建立了 TCP 连接之后执行一个 Basic.Get的操作,那么首先是由 slave 将 Basic.Get 请求发往 master,再由 master 准备好数据返回给slave,最后由 slave 投递给消费者。

在这里插入图片描述

2.1.1 集群结构

  • 如下图,集群一共三个节点,broker1、broker2、broker3。每个broker节点都包含1个镜像队列的master 和2 个镜像队列的slave。
    • qingjun_queue镜像队列的负载大多都集中在broker1上,baimu_queue镜像队列的负载大多都集中在broker2上,wuhan_queue镜像队列的负载大多都集中在broker3 上。
    • 只要确保镜像队列的 master 节点均匀散落在集群中的各 Broker 节点上就可以确保很大程度上的负载均衡。为什么不是绝对?因为每个队列的流量会有不同,因此均匀散落各个队列的 master 也无法确保绝对的负载均衡)。
  • 注意事项
    • rabbitmq镜像队列同时支持发送方确认机制(publisher confirm )和事务机制。
      • 在事务机制中,只有当前事务在全部镜像中执行之后,客户端才会收到 Tx.Commit-ok 的消息。
      • 在publisher confirmm 机制中,生产者进行当前消息确认的前提是该消息被全部进行所接收了。

在这里插入图片描述

2.2 镜像结构

  • 镜像队列结构和普通队列结构不同点在于backing_queue的不同,普通队列使用的是rabbit_variable_queue,而镜像队列使用的backing_queue内部包裹了普通backing_queue进行本地消息消息持久化处理,在此基础上增加了将消息和 ack 复制到所有镜像的功能。
  • 如下图,master使用的backing_queue是 rabbit_mirror_queue_master,slave使用的backing_queue是rabbit_mirror_queue_slave。
  • 普通队列结构

在这里插入图片描述

  • 镜像队列结构
    在这里插入图片描述

2.2.1 组播GM

  • GM的作用:
    • 所有对 rabbit_mirror_queue_master 的操作都会通过组播 GM(GuaranteedMulticast)的方式同步到各个 slave 中。
    • GM 负责消息的广播,rabbit_mirror_queue_slave 负责回调处理,而 master 上的回调处理是由 coordinator 负责完成的。
    • 除了Basic.Publish,所有的操作都是通过 master 来完成的,master 对消息进行处理的同时将消息的处理通过 GM 广播给所有的 slave,slave 的 GM 收到消息后,通过回调交由rabbit_mirror_queue_slave进行实际的处理。

2.2.1.1 实现原理

  • GM 模块是通过组播通信协议来实现,该协议能够保证组播消息的原子性。换言之,保证组中活着的节点要么都收到消息,要么都收不到。
  • 实现过程:
    • 将所有的节点形成一个循环链表,每个节点都会监控位于自己左右两边的节点。
      • 当有节点新增时,相邻的节点保证当前广播的消息会复制到新的节点上。
      • 当有节点失效时,相邻的节点会接管以保证本次广播的消息会复制到所有的节点。
    • master 和 slave 上的组播GM会形成一个组 (gm group),这个组的信息会记录在 Mnesia 中。
    • 不同的镜像队列形成不同的组。操作命令从 master 对应的 GM 发出后,顺着链表传送到所有的节点。由于所有节点组成了一个循环链表,master 对应的 GM 最终会收到自己发送的操作命令,这个时候 master 就知道该操作命令都同步到了所有的 slave 上。

在这里插入图片描述

2.2.1.2 加入新节点

  • 如下图,新增了一个节点4,整个过程就像在链表中间插入一个节点。
  • 注意事项:
    • 每当个节点加入或者重新加入到这个镜像链路中时,之前队列保存的内容会被全部清空。

在这里插入图片描述

2.2.1.3 节点宕机的影响

  • 当 slave 挂掉之后,除了与 slave 相连的客户端连接全部断开,没有其他影响。
  • 当 master 挂掉之后,会有以下连锁反应:
    • 第一步,先与 master 连接的客户端连接全部断开。
    • 第二步,选举最老的slave作为新的 master。因为最老的 slave 与旧的 master 之间的同步状态是最好的。如果此时所有 slave 处于未同步状态,则未同步的消息会丢失。
    • 第三步,新的 master 重新入队所有 unack 的消息。因为新的 slave 无法区分这些 unack 的消息是否已经到达客户端,或者是 ack 信息丢失在老的 master 链路上,再或者是丢失在老的 master 组播 ack 消息到所有 slave 的链路上,所以出于消息可靠性的考虑,重新入队所有 unack 的消息,带来的弊端就是客户端可能会有重复消息。
    • 第四步,若客户端连接着 slave,并且 Basic.Consume 消费时指定了 x-cancel-on-ha:failover 参数,那么断开时客户端会收到一个 Consumer Cancellation Notifcation 的通知,消费者客户端中会回调 consumer 接口的 handleCancel 方法。如果未指定 x-cancel-on-ha-failover 参数,那么消费者将无法感知 master 宕机。

2.3 配置镜像队列

  • 镜像队列的配置主要是通过添加相应的 Policy 来完成的,两种方式,一是在代码里提前写好配置,二是使用管理命令配置。

  • 注意事项:

    • 镜像队列中最后一个停止的节点会是 master,启动顺序必须是 master 先启动。
    • 如果 slave先启动,它会先等待30 秒等待master 的启动,Master节点加入到集群中后,slave才启动。
    • 如果 30 秒内 master没有启动,slave 会自动停止。
    • 当所有节点因故(断电等) 同时离线时,每个节点都认为自己不是最后一个停止的节点,要恢复镜像队列,可以尝试在 30 秒内启动所有节点。

2.3.1 定义参数

  • 参数含义:

    • ha-mode:指明镜像队列的模式,可选项有 all、exactly、nodes,默认为 all。
      • all:表示在集群中所有的节点上进行镜像。
      • exactly:表示在指定个数的节点上进行镜像,节点个数由 ha-params 指定。
      • nodes: 表示在指定节点上进行镜像,节点名称由 ha-params 指定,节点的名称通常类似于 rabbit@hostname ,可以通过rabbitmqctl_cluster_status命令查看。
    • ha-params:不同的 ha-mode 配置中需要用到的参数。
    • ha-sync-mode:队列中消息的同步方式,可选项有 automatic(自动) 和manual(手动)。
    • ha-promote-on-shutdown:可选参数when-synced(何时同步)和always(始终同步)。
    • ha-promote-on-failure:可选参数when-synced(何时同步)和always(始终同步)。
  • 注意事项:

    • ha-mode参数对排他(exclusive) 队列不生效,因为排他队列是连接独占的,当连接断开时队列会自动删除,所以实际上这个参数对排他队列没有任何意义。
    • 将新节点加入已存在的镜像队列时,默认情况下 ha-sync-mode 取值为 manual(手动),镜像队列中的消息不会主动同步到新的 slave 中,除非显式调用同步命令。当调用同步命令后,队列开始阻塞,无法对其进行其他操作,直到同步完成。
    • 当 ha-sync-mode 设置为 automatic(自动)时,新加入的 slave 会默认同步已知的镜像队列。由于同步过程的限制,所以不建议对生产环境中正在使用的队列进行操作。
    • 当所有slave都出现未同步状态,且ha-promote-on-shutdown参数设为 always,那么不论 master 因为何种原因停止,slave 都会接管 master,优先保证可用性,存在消息丢失情况。当ha-promote-on-shutdown参数设置为 when-synced(默认)时,分两种情况:
      • 若master 因主动原因停掉,比如通过rabbitmgctl stop命令停止,那么slave不会接管 master,此时镜像队列不可用。
      • 若master 因被动原因停掉,比如 Erlang 虚拟机或者操作系统崩溃,那么 slave 会接管 master。

在这里插入图片描述

2.3.2 命令配置

  • 命令格式:
    • rabbitmqctl set_policy [-p vhost] [–prioritypriority] [–apply-to apply-to] {name} {pattern} {definition}
  • 参数释义:
    • [-p vhost]参数:可选参数,针对指定vhost下的queue进行设置。
    • [–prioritypriority]:可选参数,policy的优先级。
    • [–apply-to apply-to ]参数:可选参数,指定对象为交换器还是队列。
    • {name}参数:自定义策略名称。
    • {pattern}参数: queue的匹配模式(正则表达式)
    • {definition}参数:ha-mode 、ha-params、ha-sync-mode三部分。

1.查看要进行镜像的队列。

在这里插入图片描述
2. 设置策略。

# 优先级为0。
#指定对象为所有交换器。
#策略名称为qingjun_policy。
#匹配正则为"以qingjun开头的所有交换器"。
#镜像策略为,在3个节点上进行镜像,并设置消息同步方式为自动同步。
[root@node1 ~]# rabbitmqctl set_policy --priority 0 --apply-to exchanges  qingjun_policy  "^qingjun*" '{"ha-mode":"exactly","ha-params":3,"ha-sync-mode":"automatic"}'

在这里插入图片描述

  1. 查看结果。

在这里插入图片描述
4. 查看状态

在这里插入图片描述
在这里插入图片描述

2.3.4 相关命令

2.3.4.1 查看节点消息同步状态

[root@node1 ~]# rabbitmqctl  list_queues name slave_pids synchronised_slave_pids

在这里插入图片描述

2.3.4.2 取消某队列同步消息功能

#取消qingjue_queue队列的消息同步功能,注意这个队列是能匹配到上面设置的镜像队列策略的。
[root@node1 ~]# rabbitmqctl  cancel_sync_queue qingjue_queue

在这里插入图片描述

2.3.4.3 手动同步某队列消息

# 手动给qingjue_queue队列进行消息同步,注意这个队列是能匹配到上面设置的镜像队列策略的。
[root@node1 ~]# rabbitmqctl  sync_queue qingjue_queue

在这里插入图片描述

三、网络分区

  • 网络分区的意义

    • rabbitmq集群的网络分区的容错性不是很高,一般情况可以使用 Federation 或者 Shovel插件就可以解决广域网中的使用问题。不过即使是在局域网环境下,网络分区也不可能完全避免,网络设备(比如中继设备、网卡) 出现故障也会导致网络分区。极端情况下还会造成数据丢失,影响服务的可用性。
    • 当一个集群发生网络分区时,这个集群会分成两个部分或者更多,它们各自为政,互相都认为对方分区内的节点已经挂了,包括队列、交换器及绑定等元数据的创建和销毁都处于自身分区内,与其他分区无关。如果原集群中配置了镜像队列,而这个镜像队列又牵涉两个或者更多个网络分区中的节点时,每一个网络分区中都会出现一个 master 节点,对于各个网络分区,此队列都是相互独立的。当然也会有一些其他未知的、怪异的事情发生。
    • 在一致性数据模型下,若出现网络波动或者网络故障等异常情况,会导致整个数据链的性能就会大大降低。例如有A、B、C、D四节点为一个数据链,倘若其中的 C 节点网络异常,那么整个 A——> B——> C——>D——> A 的数据链就会被阻塞,继而相关服条也会被阻塞,这种情况下就需要将异常节点C剥离整个分区,以确保rabbitmq服务的可用性及可靠性。等待网络恢复之后,可以进行相应的处理来将此前的异常节点加入集群中。
  • 网络分区的影响:

    • 数据丢失;
    • 服务阻塞不可用;
    • 网络恢复后,网络分区状态仍然存在。

3.1 网络分区的判断

  • 判断机制:
    • rabbitmq集群节点内部通信端口默认为 25672,两两节点之间都会有信息交互。如果某节点出现网络故障,或者是端口不通,则会致使与此节点的交互出现中断,这里就会有个超时判定机制,继而判定网络分区。
    • 超时判定机制与 net_ticktime 参数有关,该参数默认值为 60 秒。若超时,则会有 net_tick_timeout 的信息报出。这个参数与 heartbeat_time 有些区别,heartbeat_time 是指客户端与 RabbitMQ 服务之间通信的心跳时间,针对 5672 端口而言。
  • 节点之间的应答机制(判断流程):
    • rabbitmq集群内部的每个节点之间会每隔四分之一的net_ticktime 计一次应答 (tick)。若有任何数据被写入节点中,则此节点被认为已经被应答 (ticked) 了。如果连续 4 次,某节点都没有被 ticked,则可以判定此节点已处于“down”状态,其余节点可以将此节点剥离出当前分区。

3.1.1 应答时间范围

  • 如下图,将连续 4 次的 tick 时间记为 T,那么 T 的取值范围为:0.75 * net_ticktime < T<1.25 * net_ticktime。
  • 图中每个节点代表一次 tick 判定的时间戳,在2个临界值 0.75 * net_ticktime 和1.25 * net_ticktime 之间可以连续执行 4 次的 tick 判定。默认情况下,在 45s < T< 75s之间会判定出 net_tick_timeout。

在这里插入图片描述

3.1.2 判定方式

3.1.2.1 日志方式

  • rabbitmq不仅会将队列、交换器及绑定等信息存储在 Mnesia 数据库中,而且许多围绕网络分区的一些细节也都和这个Mnesia的行为相关。
  • 如果一个节点不能在下时间连上另一个节点,那么 Mnesia 通常认为这个节点已经挂了,就算之后两个节点又重新恢复了内部通信,但是这两个节点都会认为对方已经挂了,Mnesia 此时认定了发生网络分区的情况。这些会被记录到RabbitMO 的服务日志之中。

在这里插入图片描述

3.1.2.2 命令查看

  • 通过命令rabbitmqctl cluster_status 可以看到集群相关信息。
    • 当没有发生网络分区时,在Network Partitions这一块显示无。
    • 当发生网络分区时,Network Partitions这一块会显示相关信息。

在这里插入图片描述
在这里插入图片描述

3.1.2.3 监控页面提示

  • 也可以通过 Web 管理界面来查看。如果出现了下图这种告警,即发生了网络分区。

在这里插入图片描述

3.1.2.4 API查看

  • 第三种,通过 HTTP API 的方式调取节点信息来检测是否发生网络分区。
  • 其中会有 partitions 的相关项,如果在其中发现 partitions 项中有内容则为发生了网络分区。举例,将 node2 分离出 nodel和 node3的主分区之后,调用/api/nodes 这个接口的部分信息
#在node1节点上查看,partitions一栏显示有node2节点,说明node1和node2节点发生了网络分区。
[root@node1 ~]# curl  -XGET http://192.168.130.129:15672/api/nodes?pretty -i -u qingjun:citms -H "content-type:application/json"

在这里插入图片描述

3.2 模拟网络分区

  • 模拟网络分区的方式有多种,主要分为以下 3 大类:
    • iptables 封禁/解封 IP 地址或者端口号。
    • 关闭/开启网卡。
    • 挂起/恢复操作系统

3.2.1 封禁端口

  • 若是通过防火墙屏蔽端口只能模拟出net_tick_timeout,不能触发网络分区。

在这里插入图片描述

  • 由于rabbitmq集群内部节点通信端口默认为 25672,可以封禁25672端口方式来模拟出net_tick_timeout。开启防火墙只能模拟触发节点的net_tick_timeout,但是模拟不了节点的网络分区现象。
  • 比如我这里集群有3个节点,node1、node2、node3。此时我们要模拟 node2 节点被剥离出当前分区的情形,即模拟[nodel,node3]和[node2]两个分区。就在 node2节点执行封禁端口命令。

1.封禁node2节点上的25672端口。

[root@node2 ~]# iptables -A INPUT -p tcp --dport 25672 -j DROP
[root@node2 ~]# iptables -A OUTPUT -p tcp --dport 25672 -j DROP

2.此时可以查看node1和node3节点日志,显示node2已经触发了节点之间的应答机制。

在这里插入图片描述
3.接触node2节点上的25672封禁,此时才会判定node2节点发生了网络分区。

[root@node2 ~]# iptables -D OUTPUT 1
[root@node2 ~]# iptables -D INPUT 1

4.此时再去查看node1和node3节点日志,显示node2节点出现了网络分区。而node2节点上的日志显示,node1和node3节点已经掉线。

在这里插入图片描述
在这里插入图片描述

5.分别查看三个节点上集群状态。

在这里插入图片描述
在这里插入图片描述

4.查看web监控页面。

在这里插入图片描述

3.2.2 封禁IP

  • 假设整个rabbitmq集群的节点名称与其IP地址对应如下:
    node1 192.168.130.129
    node2 192.168.130.130
    node3 192.168.130.131
  • 若要模拟出[node1,node3]和[node2]两个分区的情形,可以在 node2 节点上执行封禁命令。
#封禁。
iptables -I INPUT -s 192.168.130.129 -j DROP
iptables -I INPUT -S 192.168.130.131 -j DROP
#解封。
iptables -D INPUT 1
iptables -D INPUT 1
  • 也可以分别在 node1 和 node3 节点上执行封禁命令。
#封禁。
iptables -I INPUT -s 192.168.130.130 -j DROP
#解封。
iptables -D INPUT 1
  • 如果集群的节点部署跨网段,可以采取禁用整个网络段的方式模拟网络分区。
  • 假设rabbitmq集群中 3 个节点和其对应的 IP 关系如下:
    node1 192.168.0.2
    node2 192.168.1.3
    node3 192.168.0.4
  • 模拟出[node1,node3]和[node2]两个分区的情形,可以在 node2 节点上封禁命令。
#封禁。
iptables -I INPUT -s 192.168.0.0/24 -j DROP
#解封. 
iptables -D INPUT 1

3.2.3 封禁网卡

  • 先使用 ifconfig 命令来查询出当前的网卡编号,如下所示,一般情况下单台机器只有-个网卡。
[root@node1 ~]# ifconfig

在这里插入图片描述

  • 同样假设 node1、node2 和 node3 这三个节点组成 RabbitMQ 集群,node2 的网卡编号为ens33,此时要模拟网络分区[nodel,node3]和node2]的情形,需要在 node2 上执行封禁网卡命令。
#封禁。
ifdown ens33 或者 systemctl stop  network 
#解封。
ifup ens33  或者 systemctl start  network 

3.2.4 挂起恢复操作系统

  • 操作系统的挂起和恢复操作也会导致集群内节点的网络分区。因为发生挂起的节点不会认为自身已经失败或者停止工作,但是集群内的其他节点会这么认为。
  • 如果集群中的一个节点运行在一台笔记本电脑上,然后你合上了笔记本电脑,那么这个节点就挂起了。或者一个更常见的现象,集群中的一个节点运行在某台虚拟机上,然后虚拟机的管理程序挂起了这个虚拟机节点,这样节点就被挂起了。在等待节点应答时间后,判定出 net_tick_timeout,再恢复挂起的节点即可以复现网络分区。

3.3 网络分区的影响

  • 未配置镜像队列情况下:
    • 对于未配置镜像的集群,网络分区发生之后,队列也会伴随着宿主节点而分散在各自的分区之中。
      • 对于消息发送方而言,可以成功发送消息,但是会有路由失败的现象,要需要配合 mandatory 等机制保障消息的可靠性。
      • 对于消息消费方来说,有可能会有诡异不可预知的现象发生,比如对于已消费消息的 ack 会失效。如果网络分区发生之后,客户端与某分区重新建立通信链路,其分区中如果没有相应的队列进程,则会有异常报出。如果从网络分区中恢复之后,数据不会丢失,但是客户端会重复消费。
  • 已配置镜像队列情况下:
  • 当镜像配置都是 ha-sync-mode=automatic 时,
    • 若有新的 slave 出现时,此 slave 会自动同步 master 中的数据。同步过程中,集群的整个服务都不可用,客户端连接会被阻塞。
    • 若master 中有大量的消息堆积,必然会造成 slave 的同步时间增长,进步影响了集群服务的可用性。
  • 当镜像配置都是 ha-sync-mode=manual时,
    • 若有新的 slave 创建时,此slave不会去同步 master 上旧的数据,如果此时 master 节点又发生了异常,那么此部分数据将会丢失同样 ha-promote-on-shutdown 这个参数的影响也需要考虑进来。

3.4 处理网络分区

3.4.1 手动处理

  • 恢复步骤:
    • 第一步,挑选一个信任分区。
    • 第二步,重启非信任分区中的节点,若重启后还有网络分区的告警,再紧接着重启信任分区中的节点。
  • 挑选信任分区:
    • 挑选信任分区有几个指标,优先级从前到后为:
      • 分区中要有 disc 节点;
      • 分区中的节点数最多分区中的队列数最多;
      • 分区中的客户端连接数最多。
  • 重启方式(2种方式):
    • 第一种:先rabbitmqctl stop命令关闭,再用 rabbitmq-server -detached 命令启动。
    • 第二种,先rabbitmqctl stop_app命令关闭,再用 rabbitmqctl start_app 命令启动。(推荐)
  • 重启顺序(2种方式):
    • 第一种,先停止其他非信任分区中的所有节点,然后再启动这些节点。如果此时还有网络分区的告警,则再重启信任分区中的节点以去除告警。比如我上面这种网络分区情况,先关闭node2上的服务,在启动node2服务,若还存在网络分区告警,则在重启node1和node3节点。
    • 第二种,先关闭整个集群中的节点,然后再启动每一个节点,这里需要确保启动的第一个节点在信任的分区之中。
  • 注意事项:
    • 在选择哪种重启顺序之前,首先考虑一下队列“漂移”的现象。所谓的队列“漂移”是在配置镜像队列的情况下才会发生的。
    • 一定要按照这里提及的重启方式重启。若选择挨个节点重启的方式,虽也可以处理网络分区,但是会出现Mnesia 内容权限的归属问题,而且还可能会引起二次网络分区的发生。比如有两个分区[node1,node2]和node3,node4],其中[node1,node2]为信任分区。此时若按照挨个重启的方式进行重启,比如先重启 node3,在 node3 节点启动之时无法判断其节点的 Mnesia 内容是向node1,node2]分区靠齐还是向 node4 节点靠齐。至此,如果挨个一轮重启之后,最终集群中的Mnesia 数据是[node3,node4]这个非信任分区,就会造成无法估量的损失。挨个节点重启。

3.4.1.1 镜像队列漂移现象

  • 漂移现象:
    • 若存在镜像队列,从发生网络分区到恢复的过程中队列可能会出现“漂移”的现象。所谓漂移就是队列的master节点都“漂移”到一个节点上,除了发布消息之外,其他操作都在master节点上完成,从而造成负载不均衡。
  • 缓解方法:
    • 可以重启之前先删除镜像队列的配置,这样能够在一定程度上阻止队列的“过分漂移”,即阻止可能所有队列都“漂移”到一个节点上的情况。
  • 处理方法:
    • 第一种,最常见的就是直接在监控页面上删除。
      在这里插入图片描述
      在这里插入图片描述
    • 第二种,若事先没有开启 RabbitMQ Management 插件,就只能使用 rabbitmqctl 工具的方式。但是需要在每个分区上都执行删除镜像队列配置的操作,以确保每个分区中的镜像都被删除。比如我这里就要在node1和node2节点上都要执行删除命令,或者在node3和node2节点上执行。
      • 查看命令:rabbitmqctl list_policies
      • 删除命令:rabbitmqctl clear_policy [-p vhost] {mirror_queue_name}
[root@node1 ~]# rabbitmqctl list_policies

[root@node1 ~]# rabbitmqctl clear_policy baimu_policy

在这里插入图片描述

3.4.1.2 处理流程总结

  • 网终分区处理步骤总结如下:
    • 步骤 1: 先挂起生产者和消费者进程。这样可以减少消息不必要的丢失,若进程数过多情形又比较紧急,也可跳过此步骤。
    • 步骤 2:删除镜像队列的配置。
    • 步骤 3:挑选信任分区。
    • 步骤4:关闭非信任分区中的节点。采用 rabbitmqctl stop_app 命令关闭。
    • 步骤 5:启动非信任分区中的节点。采用与步骤4 对应的 rabbitmqctl start_app命令启动。
    • 步骤 6:检查网络分区是否恢复。若已经恢复,则转步骤 8;若还有网络分区的报警,则转步骤 7。
    • 步骤 7:重启信任分区中的节点。
    • 步骤 8:添加镜像队列的配置。
    • 步骤 9:恢复生产者和消费者的进程。

3.4.2 自动处理网络分区

  • 在 rabbitmg.config 配置文件中配置 cluster_partition_handling参数即可实现相应的功能。有三种方法自动地处理网络分区:pause_minority 模式、pause_if_all_down 模式和 autoheal 模式。
  • 默认是 ignore 模式,即不自动处理网络分区,所以在这种模式下,当网络分区的时候需要人工介入。

在这里插入图片描述

3.4.2.1 pause_minority 模式

  • 若cluster_partition_handling = pause_minority,当发生网络分区时,集群中的节点在观察到某些节点“down”掉的时候,会自动检测其自身是否处于“少数派”(分区中的节点小于或者等于集群中一半的节点数),rabbitmq会自动关闭少数派节点的rabbitmq应用,Erlang虚拟机不关闭。

  • 根据 CAP3 原理,这里保障了 P,即分区耐受性。这样确保了在发生网络分区的情况下,大多数节点(当然这些节点得在同一个分区中) 可以继续运行。“少数派”中的节点在分区开始时会关闭,当分区结束时又会启动。相当于执行了 rabbitmgctl stop_app命令。处于关闭的节点会每秒检测一次是否可连通到剩余集群中,如果可以则启动自身的应用。相当于执行 rabbitmqctl start app 命令。

  • CAP 原理:

    • CPA原理,又称之为 CAP 定理,是指在一个分布式系统中,Consistency (一致性)、Availability (可用性)和 Partition tolerance
      (分区耐受性) 三者不可兼得。
  • 注意事项:

    • 若集群中只有两个节点时,不适合采用 pause_minority 模式。因为其中任何一个节点失败而发生网络分区时两个节点都会关闭。当网络恢复时,有可能两个节点会自动启动恢复网络分区,也有可能仍保持关闭状态。
    • 若集群节点数远大于 2 个时,采用pause_minority 模式比 ignore 模式更加可靠,特别是网络分区通常是由单节点网络故障而脱离原有分区引起的。
    • 若出现对等分区时,会关闭这些分区内的所有节点,只有等待网络恢复之后,才会自动启动所有的节点以求从网终分区中恢复。比如集群组成为[ node1,node2,node3,node4 ]四个节点,由于某种原因分裂成类似[node1,node2]和[node3,node4]这两个网络分区的情形。这种情况在跨机架部署时就有可能发生,当 node1和node2 部署在机架 A 上,而 node3 和 node4 部署在机架 B 上,那么有可能机架 A 与机架 B之间网络的通断会造成对等分区的出现。对于[node1,node2]和[node3,node4]而言,这四个节点上的rabbitmq应用都会被关闭。

3.4.2.2 pause_if_all_down 模式

  • 若cluster_partition_handling = pause_if_all_down,rabbitmq集群中的节点在和配置检查节点列表中的任何节点不能交互时才会关闭。

在这里插入图片描述

  • 如上图配置表示:
    • 若一个节点与rabbitmq_1@node1或rabbitmq_2@node2节点无法通信时,则会关闭自身的rabbitmq应用。
    • 若是rabbitmq_1@node1或rabbitmq_2@node2本身发生了故障造成网络不可用,而其他节点都是正常的情况下,这种规则会让所有的节点中rabbitmq应用都关闭,待rabbitmq_1@node1或rabbitmq_2@node2中的网络恢复之后,各个节点再启动自身应用以从网络分区中恢复。
  • 注意事项:
    • pause_if_all_down 模式下有 ignore 和 autoheal 两种配置。若出现对等分区时,node1 和 node2 部署在机架 A 上,而 node3 和 node4 部署在机架 B 上。而配置里是node1和node3节点名称,那么当机架A 和机架B 的通信出现异常时,由于 nodel 和 node2 保持着通信,node3 和 node4 保持着通信,这 4 个节点都不会自行关闭,但是会形成两个分区,所以这样不能实现自动处理的功能。所以如果将配置中的 ignore替换成 autoheal 就可以处理此种情形。
    • 在 autoheal 模式下,如果集群中有节点处于非运行状态,那么当发生网络分区的时候,将不会有任何自动处理的动作。
  • autoheal 模式:
    • 在 autoheal 模式下,当认为发生网络分区时,rabbitmq会自动决定一个获胜 (winning)的分区,然后重启不在这个分区中的节点来从网络分区中恢复。
  • 获胜分区:
    • 一个获胜的分区是指客户端连接最多的分区,若产生一个平局,即有两个或者多个分区的客户端连接数一样多,那么节点数最多的一个分区就是获胜分区。若此时节点数也一样多,将以节点名称的字典序来挑选获胜分区。
  • 总结:
    • 对于 pause-minority 模式,关闭节点的状态是在网络故障时,也就是判定出 net_tick_timeout之时,会关闭“少数派”分区中的节点,等待网络恢复之后,即判定出网络分区之后,启动关闭的节点来从网络分区中恢复。
    • autoheal 模式在判定出 net_tick_timeout之时不做动作,要等到网络恢复之时,在判定出网络分区之后才会有相应的动作,即重启非获胜分区中的节点。

3.4.2.3 各模式优缺点

  • 每种模式优缺点:
    • ignore 模式:发生网络分区时,不做任何动作,需要人工介入。
    • pause-minoriy 模式:对于对等分区的处理不够优雅,可能会关闭所有的节点。一般情况下,可应用于非跨机架、奇数节点数的集群中。
    • pause-if-all-down 模式:对于受信节点的选择尤为考究,尤其是在集群中所有节点硬件配置相同的情况下。此种模式可以处理对等分区的情形。
    • autoheal 模式:可以处于各人情形下的网络分区。但是如果集群中有节点处于非运行状态,则此种模式会失效。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

rabbitmq基础9——流控、镜像队列、网络分区 的相关文章

  • 跟踪 Linux 程序中活跃使用的内存

    我想跟踪各种程序在特定状态下接触了多少内存 例如 假设我有一个图形程序 最小化时 它可能会使用更少的内存 因为它不会重新绘制窗口 这需要读取图像和字体并执行大量库函数 这些对象仍然可以在内存中访问 但实际上并没有被使用 类似的工具top它们
  • 通过特定分隔符删除字符串

    我的文件中有几列 其中第二列有 分隔符 我想删除第二列中的第一个 第三个和第四个字符串 并将第二个字符串留在该列中 但我有正常的分隔符空间 所以我不知道 input 22 16050075 A G 16050075 A G 22 16050
  • 如何禁用 GNOME 桌面屏幕锁定? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何阻止 GNOME 桌面在几分钟空闲时间后锁定屏幕 我已经尝试过官方手册了在红帽 https access redhat com doc
  • Jenkins中找不到环境变量

    我想在詹金斯中设置很多变量 我试过把它们放进去 bashrc bash profile and profile of the jenkins用户 但 Jenkins 在构建发生时找不到它们 唯一有效的方法是将所有环境变量放入Jenkinsf
  • Linux中的CONFIG_OF是什么?

    我看到它在很多地方被广泛使用 但不明白在什么场景下我需要使用它 What is 配置 OF OF 的全名是什么 打开固件 这是很久以前发明的 当时苹果公司正在生产基于 PowerPC CPU 的笔记本电脑 而 Sun Microsystem
  • chown:不允许操作

    我有问题 我需要通过 php 脚本为系统中的不同用户设置文件所有者权限 所以我通过以下命令执行此操作 其中 1002 是系统的用户 ID file put contents filename content system chown 100
  • 使用 sed 更新 xml 属性(Windows + cygwin 和 Linux)?

    我需要使用 sed 命令对 xml 文件进行更新 但我在这方面遇到了麻烦 它需要在 Windows 使用 cygwin 和 Linux 上运行 XML 具有以下元素
  • fopen 不返回

    我在 C 程序中使用 fopen 以只读模式 r 打开文件 但就我而言 我观察到 fopen 调用没有返回 它不返回 NULL 或有效指针 执行在 fopen 调用时被阻止 文件补丁绝对正确 我已经验证过 并且不存在与权限相关的问题 任何人
  • 如何有效截断文件头?

    大家都知道truncate file size 函数 通过截断文件尾部将文件大小更改为给定大小 但是如何做同样的事情 只截断文件的尾部和头部呢 通常 您必须重写整个文件 最简单的方法是跳过前几个字节 将其他所有内容复制到临时文件中 并在完成
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • arm64和armhf有什么区别?

    Raspberry Pi Type 3 具有 64 位 CPU 但其架构不是arm64 but armhf 有什么区别arm64 and armhf armhf代表 arm hard float 是给定的名称Debian 端口 https
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • PHP 从命令行启动 gui 程序,但 apache 不启动

    首先 我阅读了有类似问题的人的一些帖子 但所有答案都没有超出导出 DISPLAY 0 0 和 xauth cookies 这是我的问题 提前感谢您的宝贵时间 我开发了一个小库 它使用 OpenGL 和 GLSL 渲染货架 过去几天我将它包装
  • Linux 可执行文件与 OS X“兼容”吗?

    如果您在基于 Linux 的平台上用 C 语言编译一个程序 然后将其移植以使用 MacOS 库 它会工作吗 来自编译器的核心机器代码在 Mac 和 Linux 上兼容吗 我问这个问题的原因是因为两者都是 基于 UNIX 的 所以我认为这是真
  • jpegtran 优化而不更改文件名

    我需要优化一些图像 但不更改它们的名称 jpegtran copy none optimize image jpg gt image jpg 但是 这似乎创建了 0 的文件大小 当我对不同的文件名执行此操作时 大小仍然完全相同 怎么样 jp
  • 如何授予 apache 使用 NTFS 分区上的目录的权限?

    我在一台带有 20GB 硬盘的旧机器上运行 Linux Lubutu 12 10 我有一个 1 TB 外部硬盘 上面有一个 NTFS 分区 在该分区上 有一个 www 目录 用于保存我的网页内容 它在启动时自动安装为 media t515
  • 为什么我可以直接从 bash 执行 JAR?

    我是一个长期从事 Java 工作的人 并且知道运行带有主类的 JAR 的方法MANIFEST MFJar 中的文件很简单 java jar theJar jar 我用它来启动 Fabric3 服务器 包含在bin server jar在其标
  • SSE:跨页边界的未对齐加载和存储

    我在页面边界旁边执行未对齐加载或存储之前读过某处 例如使用 mm loadu si128 mm storeu si128内在函数 代码应首先检查整个向量 在本例中为 16 个字节 是否属于同一页 如果不属于同一页 则切换到非向量指令 我知道
  • 在我的 index.php 中加载 CSS 和 JS 等资源时出现错误 403

    我使用的是 Linux Elementary OS 并在 opt 中安装了 lampp My CSS and JS won t load When I inspect my page through browser The console
  • jq中如何分组?

    这是 json 文档 name bucket1 clusterName cluster1 name bucket2 clusterName cluster1 name bucket3 clusterName cluster2 name bu

随机推荐

  • FISCO BCOS(二十九)———区块链浏览器

    一 浏览器主要用途 区块链浏览器将区块链中的数据可视化 并进行实时展示 方便用户以Web页面的方式 获取当前区块链中的信息 二 一键部署 2 1 环境要求 环境 版本 Java JDK8或以上版本 MySQL MySQL 5 6或以上版本
  • UE4-VaRest客户端上传玩家得分并获取排行榜

    排行榜相关 1 上传得分 2 获取玩家排名 3 获取排行榜 1 上传得分 2 获取玩家排名 3 获取排行榜
  • 一个环境变量导致运行报错Exception in thread "main" java.lang.NoClassDefFoundError:

    昨天下午编译通过就一直报错Exception in thread main java lang NoClassDefFoundError 早上终于调通了 加油 1 安装与配置 1 在我的电脑C盘里安装了SDK 路径是这样的 C Progra
  • 如何卸载显卡驱动通过软件简单卸载法

    有时候需要卸载显卡的驱动时 可以通过下载这个软件来卸载 显卡驱动卸载工具 Display Driver Uninstaller 简称为DDU卸载工具 下载地址为 Official Display Driver Uninstaller DDU
  • Python爬虫爬取VIP网站

    一直有爱看美剧的习惯 一方面锻炼一下英语听力 一方面打发一下时间 之前是能在视频网站上面在线看的 可是自从广电总局的限制令之后 进口的美剧英剧等貌似就不在像以前一样同步更新了 但是 作为一个宅diao的我又怎甘心没剧追呢 所以网上随便查了一
  • 信息系统分析相关知识梳理

    一 企业信息化战略与实施 一 企业信息化 1 以数据处理为核心 围绕职能部门 有企业系统规划法 关键成功因素法 战略集合转化法 2 以企业内部管理信息系统为核心 围绕企业整体 有战略数据规划法 信息工程法 战略栅格法 3 以集成为核心 面向
  • AD20画板基本流程

    AD20画板流程 前言 一 AD库的选择与添加 二 画原理图 1 选择元器件 2 放置端口和放置线 3 标注 4 分离模块 5 将原理图更新到PCB中 1 元器件未封装 2 网络标签的网络属性没有放在放置线上 3 网络标签没有对应上 三 P
  • ESP系列模组PCB设计及天线摆放

    ESP8266 8285系列可以焊接到PCB板上 为了使模组获得最佳的射频性能 要合理设计模组和天线在底板上的摆放位置 一 布局 1 天线布局 二 电路设计 三 地层
  • JAVA开发运维(web场景漏洞与修复)

    漏洞一 fastjson lt 1 2 80 反序列化任意代码执行漏洞 修复建议 1 升级到最新版本1 2 83 https github com alibaba fastjson releases tag 1 2 83 该版本涉及auto
  • 做了一个directshow的filter,把RGB视频流变成黑白的 .

    转自 http blog csdn net mengaim cn article details 241449 做的这个directshow的filter属于transform filter 在其间 参考了 directshow的帮助文档
  • vt 在ubuntu交叉编译windows的执行文件

    参考文档 见官网 系统 ubuntu18 04 编译步骤 1 安装 goclang 下载 https golang org doc install 解压命令 tar C usr local xzf go1 14 2 linux amd64
  • Connection is read-only. Queries leading to data modification are not allowed

    看了下mysql connector 5 1 40版本中 如果设置failoverReadOnly true 即默认值 参考 链接 当mysql连接failover时 会根据jdbc连接串将当前连接的readOnly值设置为true 第8行
  • Matlab之行列向量的赋值

    在别人的matlab代码中看到 将列向量赋值给行向量 最初还以为是别人的代码有bug 实际上运行后才发现是由自己的无知造成的 因此 将如下一小段测试的代码贴出来 向量的维度由左值 被赋值的变量 决定 column 1 2 3 row 0 0
  • python程序设计报告-20191206 实验二《Python程序设计》实验报告

    学号 2019 2020 2 Python程序设计 实验二报告 课程 Python程序设计 班级 1912 姓名 陈发强 学号 20191206 实验教师 王志强 实验日期 2020年4月19日 必修 选修 公选课 1 实验内容 设计并完成
  • 7-7 12-24小时制 (15 分)

    编写一个程序 要求用户输入24小时制的时间 然后显示12小时制的时间 输入格式 输入在一行中给出带有中间的 符号 半角的冒号 的24小时制的时间 如12 34表示12点34分 当小时或分钟数小于10时 均没有前导的零 如5 6表示5点零6分
  • 雷达系统与信号处理概述(一)

    第一章 雷达系统与信号处理概述 一 目录 第一章 雷达系统与信号处理概述 一 1 1 雷达的基本功能 1 2 检测 跟踪 成像概述 1 3 检测概率和虚警概率 1 3 1检测概率 1 3 2虚警概率 1 4 雷达分辨率 1 4 1 雷达距离
  • 静态对象、全局对象与程序的运行机制

    静态对象 全局对象与程序的运行机制 1 在介绍静态对象 全局对象与程序的运行机制之间的关系之前 我们首先看一下atexit函数 atexit函数的声明为 int atexit void cdecl func void 参数为函数指针 返回值
  • vue面试题+答案,2021前端面试

    vue面试题 答案 2022前端面试 前端进阶面试题详细解答 MVC 和 MVVM 区别 MVC MVC 全名是 Model View Controller 是模型 model 视图 view 控制器 controller 的缩写 一种软件
  • 深度学习课程设计——波士顿房价预测

    基于密集连接神经网络的波士顿房价预测 摘 要 神经网络是从信息处理角度对人脑神经元网络进行抽象 建立某种模型 按不同的连接方式组成不同的网络 本文以波士顿房价这一经典数据集为基础 该数据集包含了住宅用地所占比例等13个特征 由于keras
  • rabbitmq基础9——流控、镜像队列、网络分区

    文章目录 一 流控 1 1 流控机制 1 2 流控原理 1 3 流控状态显示 1 4 流控对象 1 5 性能提升 二 镜像队列 2 1 机制原理 2 1 1 集群结构 2 2 镜像结构 2 2 1 组播GM 2 2 1 1 实现原理 2 2