####################################################
RabbitMQ High Availability
####################################################
1.高可用queue
默认情况下RabbitMQ
cluster中的queues位于单独的节点(queues被首次声明的节点),而exchanges和bindings存在于cluster中各节点。因而每个节点失效exchanges和bindings并无影响,单弱queues所在的节点失效就会影响该节点上存在的queues。但是。queues可以在多个节点上镜像。每个被镜像的queue包含一个master和一个或者多个slave。若原master失效则最旧的slave被提升为新的master。

publish到queue的message会被复制到各个slave、consumers无论从cluster中哪个节点连接都会连接到master上,对于已经自master上被确认的message各slave会丢弃。所以,queue镜像只是增强了可用性。并没有在各节点间均衡负载。

该方案需要RabbitMQ cluster, 不能再cluster内处理network partitions因而不推荐在WAN中使用,仅用于LAN。

2.配置镜像
通过policy进行,可在任意时刻更改,将non-mirrored queue改为mirrored
queue,或者反之。需注意的是non-mirrored
queue与没有slave的mirrore的queue并不相同,前者无需额外mirroring架构运行的更快。
可用的policy
ha-mode   ha-params   行为
all                              queue被mirror到cluster中所有节点。
                                 cluster中新添加节点,queue也会被mirror到该节点。
exactly   count            queue被mirror到指定数目的节点。
                                 count大于cluster中节点数则queue被mirror到所有节点。
                                 若count小于cluster中节点数,在包含mirror的某节点down后不会在其他节点建新的mirror(为避免cluster中queue migrating)
nodes     node names  queue被mirror到指定名字的节点。
                                 若任一名称在cluster中不存在并不会引发错误。
                                若指定的任何节点在queue声明时都不在线则queue在被连接到的节点创建。

关于nodes类型的policy
设置或更改nodes类型的policy可能引起原master迁移。比如原master没有出现的新的lolicy节点列表中时。RabbitMQ采取的策略是保持原master直到至少一个新的slave已经同步,一旦同步后原master马上自动失效。原consumer连接会断掉,需重连。
如,原queue在节点{A,B},A为master。来一个新的policy{C,D},会有一段时间的状态为{A,C,D},待queue同步后A上的master关闭,新的mirror为{C,D}

特殊queue:Exclusivequeues
exclusive queues不会被镜像(mirror)也不会被持久化(durable),即使被声明为如此。因为一但存放queue的节点down了上边的连接也会断掉,对于exclusive queues相关的queue会被马上删除。

3.镜像配置示例(可通过多种方式)
下面的例子将“ha.”开头的queue mirror到cluster中所有节点
rabbitmqctl   rabbitmqctl set_policy ha-all "^ha\." '{"ha-mode":"all"}'
HTTP API    PUT /api/policies/%2f/ha-all {"pattern":"^ha\.", "definition":{"ha-mode":"all"}}
Web UI        Navigate to Admin > Policies > Add / update a policy.
                  Enter "ha-all" next to Name, "^ha\." next to Pattern, and "ha-mode" = "all" in the first line next to Policy.
                  Click Add policy.

下面的例子将“two.”开头的queue mirror到cluster中两个节点,且自动同步
rabbitmqctl    rabbitmqctl set_policy ha-two "^two\." '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'
HTTP API    PUT /api/policies/%2f/ha-two {"pattern":"^two\.",
"definition":{"ha-mode":"exactly",
"ha-params":2,"ha-sync-mode":"automatic"}}
Web UI        Navigate to Admin > Policies > Add / update a policy.
                   Enter "ha-two" next to Name and "^two\." next to Pattern.
                   Enter "ha-mode" = "exactly" in the first line next to
Policy, then "ha-params" = 2 in the second line, then "ha-sync-mode" =
"automatic" in the third, and set the type on the second line to
"Number".
                   Click Add policy.

下面的例子将“nodes.”开通的queue mirror到cluster中特定的node
rabbitmqctl   rabbitmqctl set_policy ha-nodes "^nodes\." '{"ha-mode":"nodes","ha-params":["nodeA", "nodeB"]}'
HTTP API    PUT /api/policies/%2f/ha-nodes {"pattern":"^nodes\.",
"definition":{"ha-mode":"nodes", "ha-params":["nodeA", "nodeB"]}
Web UI        Navigate to Admin > Policies > Add / update a policy.
                   Enter "ha-nodes" next to Name and "^nodes\." next to Pattern.
                   Enter "ha-mode" = "nodes" in the first line next to
Policy, then "ha-params" in the second line, set the second line's type
to "List", and then enter "nodeA" and "nodeB" in the sublist which
appears.
                  Click Add policy.

4.其他注意事项
非同步的slaves
node可在任意时刻加入RabbitMQ
cluster。根据queue的policy,当一个node加入cluster时,queues可能在这个新的node上添加一个slave。此时此刻,新的slave是空的,并不包含被镜像的queue中存在的内容。该slave将接收publish到其queue的新的message。这样一来,一段时间后salve上的queue相当于被镜像的queue的“尾巴”,且随着时间的推移被镜像的queue的“头部”越来越小,而salve上的queue的“尾巴”越来越长,最终salve的内容会与master上的内容完全同步。需要注意的是,这里有个提前提条件,即客户端需从master上的queue中不断消耗既存的message以达到master和salve的同步。

因此,新添加进的slave并不能为该slave被加入前就已存在的queue内容增加额外的冗余或可用性,直至master/slave完全同步。因为执行明确的同步操作会使queue无响应,因此只允许非活跃的queues进行明确的同步操作而活跃的queues进行自然的同步操作是一种好的策略。

配置明确的同步
明确的/显示的同步操作可以以两种方式触发:手动方式和自动方式。若queue被设置为自动同步则新salve一旦被加入同步便开始进行,queue变的无响应直至同步完成。可以通过将policy中的ha-sync-mode指定为automatic来将同步设置为自动的或者将其指定为manual或者不指定将同步设置为手动的。

可通过如下命令确认哪些salve在同步:
rabbitmqctl list_queues name slave_pids synchronised_slave_pids
手动同步queue:
rabbitmqctl sync_queue name
取消queue同步:
rabbitmqctl cancel_sync_queue name
(也可在management plugin中进行)

停止nodes与同步
当停掉运行有被镜像的queue的master
node后,其他node上的slave将被提升为新的master(假定当时存在一个已完全同步的slave)。当继续停掉nodes后会达到没有多余的slave用来镜像queue的境地,queue此时只存在于一个node中,该node此时为master。若该queue被声明为持久化的,则在仅剩的node被停掉并重启后被声明为持久化的message会仍然存在。通常,这个时候再重启其余的nodes,若这些nodes之前是镜像queue的一部分,则会重新加入被镜像的queue。
然而,目前,在重新加入备镜像的queue时,salve没有办法知道自己的queue中的内容是否和master的queu中的内容存在偏差(这在
network
partition时是可能存在的),因此,目前的策略是,当salve重新加入被镜像的queue时,丢掉本地所有的内容,以空的状态开始,就好比cluster中加入了新node一样。

停止只有未同步的salves的master nodes

在关掉master
node时所有可用的salves都还未同步完的情况是可能的。为了避免message丢失,默认情况下,在有意的/可控的关闭master时(有意的停RabbitMQ服务或关闭OS)RabbitMQ不会fail

over到还未同步完成的slave上,相反整个queue将被关闭就好像未同步完成的salve不存在一样。然而,若是无意的/不可控的关闭master
node时(例如RabbitMQ server或者node crash了或者网络掉电了)将触发master fail over到slave
node即使slave还未同步完成。

若希望在所有情形下(即使slave node还未同步完成)master node都能fail over到其他slave node,则可通过将policy中的ha-promote-on-shutdown由when-synced值为always来实现。

所有slaves处于关闭状态时的master丢失
可能发生这样一种情形,在queue的所有slaves均处于关闭状态时queue的master丢失了(可控/不可控的关闭)。正常情况下queue的nodes中最后一个被关闭的会变成master,在这个节点重启时我们仍希望其作为master(因为该node可能接收了其他node未接收到的新message)。然而,当调用rabbitmqctl

forget_cluster_node命令从cluster中移除一个node时RabbitMQ会试图为master在该node上的每个queue找到一个当前被停掉的salve
node并在这个slave node重新启动后将其“提升”为新的master。若有多个node可供选择,则最近被停掉的salve
node将被选中。

这里需要理解为什么在执行forget_cluster_node命令时RabbitMQ只能选择已停止的slave来提升为master。之所以这样是因为就像“
停止nodes与同步”部分将的:任何slave node在重新启动后会清空本地所有的内容,因而只能选择还处于停止状态的salve。因此,当从cluster中移除“丢失的”master时需在slaves重启之前执行forget_cluster_node命令。

镜像队列的实现和语义

对于每个被镜像的queue存在一个master和多个slaves,各自在不同的node。slaves以完全相同的顺序执行发生在master上的操作因此可以维护与master一致的状态。publish操作仅发生在master上然后由master
broadcasts到所有的slaves。因此从被镜像的queue consume message的 client实际上是从master
consume的。

当一个slave fail后需要做的很少:master仍为master,所有的client不会被通知slave的fail,也无需其他额外的操作。注意:slave的失败可能不会被立即探测到,每个连接的流控机制的干预可以延迟message的发送。

当master fail时,其中一个slave必须被提升为master,此时会发生以下情况:
一个slave被提升为新的master。被提升的slave是“最旧”的slave。因为该slave与原master中内容完全同步的几率最大。然而,也有可能所有的salve都未与master完全同步,此时只有master中存在而slaves中不存在的message将丢失。
slave认为所有之前的consumers的连接突然断开了。因此,它重新将已经投递但还未被确认的messages重新排队。这些“未被确认的”message可能包含client已发出确认但确认在到达master前丢失了的情形也包含client已发出确认且确认已到达master但在master广播给slaves时丢失的情形。在上述任意一种情况下,新的master都必须为他认为未收到确认的message重新排队。
之前请求原master的clients被取消。
由于重新排队,从queue重新consume的clients需要知道此时可能接收到之前已经被处理过的message

在选则的salve变成master时,这段时间内发往原被镜像的queue的message不会丢失:发给被镜像的queue的message总是直接发给master和所有的slaves。因此,一旦master失败,messages将继续被发往slaves且一旦某个salve被完全提升为master这些message将被添加到queue中。

同样,clients发送的使用publisher
confirms确认的message仍然会被正确的确认即使是在message被publish和被confirm之间master(或任何的slave)fail了。因此,从publisher的角度看,发message到mirrored
queue与发message到任何其他类型的queue并无差别。

若是从mirrored
queue使用noAck=true消费message,message就有可能丢失。RabbitMQ认为一旦message被发给了noAck=true的consumer即被视为确认过了,若这时client意外的断开了,message将永远不会被收到。在mirrored

queue情况下,在master故障时queue中被发给noAck=True的consumer的message将永远不会被收到,也不会被新的master重新排队。因为正在consuming的client可能连接在存活的node上,
Consumer Cancellation
Notification机制可以用于检测是否发生了上述情况。当然,在实际应用场景中,若关心message的可靠性则建议使用noAck=false的consumer。

Publisher Confirms 和 Transactions
Mirrored queue支持Publisher Confirms 和
Transactions。在该情形下,confirms和transactions动作在queue的所有mirror中传播。如,只有transaction在queue的所有mirror中都应用后才回返回tx.commit-ok
。同样,只有queue的所有mirror都接收到message后才会给publisher以确认。

流量控制
RabbitMQ使用基于credit的算法来限制message的发送速率。Publishers只有在接收到queue的所有mirrors反馈的credit时才允许publish

message。若salves不能反馈credit则会导致publisher阻塞。Publisher会一直被阻塞直至slaves反馈credit或者直至剩余的nodes认为该slave从cluster断开连接。Erlang通过定期发送tick至所有nodes来监测连接的断开。tick的频率可通过net_ticktime参数配置。

Consumer Cancellation
从mirrored queue消费message的clients可能想要知道它们从中消费message的queue是否发生了fail
over。当mirrored queue发生了fail
over后,关于messages已被发送到哪个consumer的信息将丢失,因此所有未确认的messages会被设置redelivered
flag后重新发送。Consumers可能想要知道是否发生了这个过程。Consumer可以通过将x-cancel-on-ha-failover
设置为true来达到此目的。这样一来在failover发生时消费将取消,
consumer cancellation notification会被发出。接下来由consumer决定是否重新

参考:

http://www.rabbitmq.com/ha.html

转载: https://blog.csdn.net/zyz511919766/article/details/41896823

RabbitMQ概念及环境搭建(四)RabbitMQ High Availability的更多相关文章

  1. RabbitMQ概念及环境搭建(三)RabbitMQ cluster

    测试环境:VMS00781 VMS00782 VMS00386 (centos5.8) 1.先在三台机器上分别安装RabbitMQ Server 2.读取其中一个节点的cookie,并复制到其他节点( ...

  2. odoo开发环境搭建(四):python开发工具IDE pycharm配置

    odoo开发环境搭建(四):python开发工具IDE pycharm配置

  3. 从零搭建ES搜索服务(一)基本概念及环境搭建

    一.前言 本系列文章最终目标是为了快速搭建一个简易可用的搜索服务.方案并不一定是最优,但实现难度较低. 二.背景 近期公司在重构老系统,需求是要求知识库支持全文检索. 我们知道普通的数据库 like ...

  4. .Net RabbitMQ系列之环境搭建于RabbitMQ基本介绍

    本系列主要讲解RabbitMQ在.Net环境下的应用,由于Linux环境下,本人Linux功力有限,所以本系列的RabbitMQ跑在Windows环境中.所以的配置之类都在Windows环境中进行. ...

  5. Go语言学习之1 基本概念、环境搭建、第一个Go程序

    一.环境搭建 见我的这篇博客 https://www.cnblogs.com/xuejiale/p/10258244.html 二.golang语言特性1. 垃圾回收    1) 内存自动回收,再也不 ...

  6. Java基础学习之基础概念与环境搭建(1)

    1.Java基础概念 1.1.Java语言的特点 Java语言是简单易学的 Java语言是面向对象(封装.继承和多态) Java语言是平台无关的(一次编译,到处运行) Java语言是可靠的.安全的(异 ...

  7. QGIS 3.14插件开发——Win10系统PyCharm开发环境搭建四步走

    前言:最近实习要求做一个QGIS插件,网上关于QGIS 3.14插件开发环境搭建的文档不多,而且也不算太全面.正好实习的时候写了一个文档,在这里给大家分享一下. 因为是Word转的Markdown,可 ...

  8. 【rabbitmq】rabbitmq集群环境搭建

    安装rabbitmq-server 总共有3台虚拟机,都安装有rabbitmq服务,安装过程可参考: [rabbitmq]Centos7 下安装rabbitmq 创建用户和vhost 说明: 此步骤不 ...

  9. RabbitMQ集群环境搭建-4

    确保成功安装好JDK,erlang,RabbitMQ等,并且RabbitMQ能正常启动,多台电脑之间能互相ping得通. 1. 安装 erlang.rabbitmq 如: 192.168.1.1.19 ...

随机推荐

  1. iOS:转载:UIControl的使用

    主要功能: UIContol(控件是所有控件的基类 如:(UIButton)按钮主要用于与用户交互,通常情况下我们不会直接使用UIControl,而是子类化它. 常用属性: BOOL enabled ...

  2. strtok()函数

    strtok()这个函数大家都应该碰到过,但好像总有些问题, 这里着重讲下它 首先看下MSDN上的解释: char *strtok( char *strToken, const char *strDe ...

  3. vue设置多入口教程

    官方脚手架搭建vue项目 在src 目录下复制app内容创建test.vue,demo.vue, main.js复制main.js内容demo.js,test.js,修改一下内容 在根目录下创建tes ...

  4. Convert Sorted Array to Binary Search Tree leetcode java

    题目: Given an array where elements are sorted in ascending order, convert it to a height balanced BST ...

  5. jquery选择器的实现流程简析及提高性能建议!

    当我们洋洋得意的使用jquery强大的选择器功能时有没有在意过jquery的选择性能问题呢,其实要想高效的使用jquery选择器,了解其实现流程是很有必要的,那么这篇文章我就简单的讲讲其实现流程,相信 ...

  6. GO语言基础条件、跳转、Array和Slice

    1. 判断语句if 1. 条件表达式没有括号(这点其他语言转过来的需要注意) 2. 支持一个初始化表达式(可以是并行方式,即:a, b, c := 1, 2, 3) 3. 左大括号必须和条件语句或 e ...

  7. IPC$ 测试与防范

    物理机系统:Win7 虚拟机系统:Win2003 Netstat –an 查看本机端口 Netstat –ano 查看本机端口+PID 通过本机上操作(比如登录网站),然后命令,查看对方IP以及端口 ...

  8. java代码在开始事务后,先做了一个查询,再insert,此时会报: java.sql.SQLException: could not retrieve transation read-only status server

    解决过程: 查看mysql的事物隔离级别 SHOW VARIABLES LIKE '%iso%'; 返回结果: REPEATABLE-READ 把这个改成:READ-COMMITTED 就好了: SE ...

  9. 打开mdb文件0x80040213

    在操作数据库时,有时遇到 0x80040213的错误,这往往是路径的问题,即所操作的文件.图层.字段等不存在. 在<ArcGIS Engine地理信息系统开发从入门到精通>一书中也谈到了这 ...

  10. 《C++游戏开发》十六 游戏中的寻路算法(二):迷宫&A*算法基础

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/10289253 作者:七十一雾央 新浪微博:http: ...