zoukankan      html  css  js  c++  java
  • rabbitmq集群故障恢复

    RabbitMQ的mirror queue(镜像队列)机制是最简单的队列HA方案,它通过在cluster的基础上增加ha-mode、ha-param等policy选项,可以根据 需求将cluster中的队列镜像到多个节点上,从而实现高可用,消除cluster模式中队列内容单点带来的风险。

    在使用镜像队列之前,有几点注意事项必须熟记于心(下文中将混用主节点和master,从节点和slave):

    1. 镜像队列不能作为负载均衡使用,因为每个操作在所有节点都要做一遍。

    2. ha-mode参数和durable declare对exclusive队列都不生效,因为exclusive队列是连接独占的,当连接断开,队列自动删除。所以实际上这两个参数对exclusive队列没有意义。

    3. 将新节点加入已存在的镜像队列时,默认情况下ha-sync-mode=manual,镜像队列中的消息不会主动同步到新节点,除非显式调用同步命令。当 调用同步命令(via rabbitmqctl or web-based ui)后,队列开始阻塞,无法对其进行操作,直到同步完毕。当ha-sync-mode=automatic时,新加入节点时会默认同步已知的镜像队列。 由于同步过程的限制,所以不建议在生产环境的active队列(有生产消费消息)中操作。

    4. 每当一个节点加入或者重新加入(例如从网络分区中恢复回来)镜像队列,之前保存的队列内容会被清空。

    5. 镜像队列有主从之分,一个主节点(master),0个或多个从节点(slave)。当master宕掉后,会在slave中选举新的master。选举算法为最早启动的节点。

    6. 当所有slave都处在(与master)未同步状态时,并且ha-promote-on-shutdown policy设置为when-syned(默认)时,如果master因为主动的原因停掉,比如是通过rabbitmqctl stop命令停止或者优雅关闭操作系统,那么slave不会接管master,也就是说此时镜像队列不可用;但是如果master因为被动原因停掉,比如VM 或者操作系统 crash了,那么slave会接管master。这个配置项隐含的价值取向是优先保证消息可靠不丢失,放弃可用性。如果ha-promote-on- shutdown policy设置为always,那么不论master因为何种原因停止,slave都会接管master,优先保证可用性。

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

    8. 对于镜像队列,客户端basic.publish操作会同步到所有节点;而其他操作则是通过master中转,再由master将操作作用于salve。 比如一个basic.get操作,假如客户端与slave建立了TCP连接,首先是slave将basic.get请求发送至master,由 master备好数据,返回至slave,投递给消费者。

    9. 由8可知,当slave宕掉时,除了与slave相连的客户端连接全部断开之外,没有其他影响。当master宕掉时,会有以下连锁反应:1)与 master相连的客户端连接全部断开。2)选举最老的slave为master。若此时所有slave处于未同步状态,则未同步部分消息丢失。3)新的 master节点requeue所有unack消息,因为这个新节点无法区分这些unack消息是否已经到达客户端,亦或是ack消息丢失在到老 master的通路上,亦或是丢在老master组播ack消息到所有slave的通路上。所以处于消息可靠性的考虑,requeue所有unack的消 息。此时客户端可能受到重复消息。4)如果客户端连着slave,并且basic.consume消息时指定了x-cancel-on-ha- failover参数,那么客户端会收到一个Consumer Cancellation Notification通知,Java SDK中会回调Consumer接口的handleCancel()方法,故需覆盖此方法。如果不指定x-cancel-on-ha-failover参 数,那么消费者就无法感知master宕机,会一直等待下去。

    上面列出的注意事项整理自官方的HA文档

    下面的镜像队列恢复才是本文重点:

    * 前提:两个节点(A和B)组成一个镜像队列。

    * 场景1:A先停,B后停。

    该场景下B是master,只要先启动B,再启动A即可。或者先启动A,再在30秒之内启动B即可恢复镜像队列。

    * 场景2: A, B同时停。

    该场景可能是由掉电等原因造成,只需在30秒之内连续启动A和B即可恢复镜像队列。

    * 场景3:A先停,B后停,且A无法恢复。

    该场景是场景1的加强版,因为B是master,所以等B起来后,在B节点上调用rabbitmqctl forget_cluster_node A,解除与A的cluster关系,再将新的slave节点加入B即可重新恢复镜像队列。

    * 场景4:A先停,B后停,且B无法恢复。

    该场景是场景3的加强版,比较难处理,早在3.1.x时代之前貌似都没什么好的解决方法,可能是我不知道,但是现在已经有解决方法了,在3.4.2 版本亲测有效。因为B是master,所以直接启动A是不行的,当A无法启动时,也就没办法在A节点上调用rabbitmqctl forget_cluster_node B了。新版本中,forget_cluster_node支 持–offline参数,offline参数允许rabbitmqctl在离线节点上执行forget_cluster_node命令,迫使 RabbitMQ在未启动的slave节点中选择一个作为master。当在A节点执行rabbitmqctl forget_cluster_node –offline B时,RabbitMQ会mock一个节点代表A,执行forget_cluster_node命令将B剔出cluster,然后A就能正常启动了。最后 将新的slave节点加入A即可重新恢复镜像队列。

    * 场景5: A先停,B后停,且A、B均无法恢复,但是能得到A或B的磁盘文件。

    该场景是场景4的加强版,更加难处理。将A或B的数据库文件(默认在$RABBIT_HOME/var/lib目录中)拷贝至新节点C的目录下,再 将C的hostname改成A或B的hostname。如果拷过来的是A节点磁盘文件,按场景4处理方式;如果拷过来的是B节点磁盘文件,按场景3处理方 式。最后将新的slave节点加入C即可重新恢复镜像队列。

    * 场景6:A先停,B后停,且A、B均无法恢复,且无法得到A或B的磁盘文件。

    放弃吧,该场景下已无法恢复A、B队列中的内容了。

  • 相关阅读:
    linux之awk命令
    HDU 2097 Sky数 进制转换
    HDU 2077 汉诺塔IV
    HDU 2094 产生冠军 dfs加map容器
    HDU 2073 叠框
    HDU 2083 简易版之最短距离
    HDU 2063 过山车 二分匹配
    天梯 1014 装箱问题
    天梯 1214 线段覆盖
    天梯 1098 均分纸牌
  • 原文地址:https://www.cnblogs.com/xuliming/p/12290589.html
Copyright © 2011-2022 走看看