RabbitMQ概念及环境搭建(四)RabbitMQ High Availability
####################################################
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的更多相关文章
- RabbitMQ概念及环境搭建(三)RabbitMQ cluster
测试环境:VMS00781 VMS00782 VMS00386 (centos5.8) 1.先在三台机器上分别安装RabbitMQ Server 2.读取其中一个节点的cookie,并复制到其他节点( ...
- odoo开发环境搭建(四):python开发工具IDE pycharm配置
odoo开发环境搭建(四):python开发工具IDE pycharm配置
- 从零搭建ES搜索服务(一)基本概念及环境搭建
一.前言 本系列文章最终目标是为了快速搭建一个简易可用的搜索服务.方案并不一定是最优,但实现难度较低. 二.背景 近期公司在重构老系统,需求是要求知识库支持全文检索. 我们知道普通的数据库 like ...
- .Net RabbitMQ系列之环境搭建于RabbitMQ基本介绍
本系列主要讲解RabbitMQ在.Net环境下的应用,由于Linux环境下,本人Linux功力有限,所以本系列的RabbitMQ跑在Windows环境中.所以的配置之类都在Windows环境中进行. ...
- Go语言学习之1 基本概念、环境搭建、第一个Go程序
一.环境搭建 见我的这篇博客 https://www.cnblogs.com/xuejiale/p/10258244.html 二.golang语言特性1. 垃圾回收 1) 内存自动回收,再也不 ...
- Java基础学习之基础概念与环境搭建(1)
1.Java基础概念 1.1.Java语言的特点 Java语言是简单易学的 Java语言是面向对象(封装.继承和多态) Java语言是平台无关的(一次编译,到处运行) Java语言是可靠的.安全的(异 ...
- QGIS 3.14插件开发——Win10系统PyCharm开发环境搭建四步走
前言:最近实习要求做一个QGIS插件,网上关于QGIS 3.14插件开发环境搭建的文档不多,而且也不算太全面.正好实习的时候写了一个文档,在这里给大家分享一下. 因为是Word转的Markdown,可 ...
- 【rabbitmq】rabbitmq集群环境搭建
安装rabbitmq-server 总共有3台虚拟机,都安装有rabbitmq服务,安装过程可参考: [rabbitmq]Centos7 下安装rabbitmq 创建用户和vhost 说明: 此步骤不 ...
- RabbitMQ集群环境搭建-4
确保成功安装好JDK,erlang,RabbitMQ等,并且RabbitMQ能正常启动,多台电脑之间能互相ping得通. 1. 安装 erlang.rabbitmq 如: 192.168.1.1.19 ...
随机推荐
- OpenCV学习(40) 人脸识别(4)
在人脸识别模式类中,还实现了一种基于LBP直方图的人脸识别方法.LBP图的原理参照:http://www.cnblogs.com/mikewolf2002/p/3438698.html 在 ...
- otl翻译(11) -- OTL的迭代器
OTL stream read iterator 这个类是一个像传统的JDBC中的getter()操作一样扩展了OTL流的模板类.它现在还不支持UNICODE字符集.它对otl_refcur_stre ...
- parameter server学习
关于parameter server的学习: https://www.zybuluo.com/Dounm/note/517675 机器学习系统相比于其他系统而言,有一些自己的独特特点.例如: 迭代性: ...
- 使用route add添加路由,使两个网卡同时访问内外网
route add命令格式:route [-f] [-p] [Command] [Destination] [mask Netmask] [Gateway] [metric Metric] [if I ...
- 使用jQuery动态改变图片显示大小
当我们要显示后台传过来若干个尺寸不一的图片时,为了保证图片大小的一致性及比例的协调,需要动态改变图片显示尺寸.通过搜索,我们可以从网上找到实现此 功能的jQuery代码如下.这段代码可以使图片的大小保 ...
- MySQL 动态sql语句运行 用时间做表名
1. 描写叙述 在使用数据的时候,我时候我们须要非常多数据库,并且想用时间来做表名以区分.可是MySQL在存储过程中不支持使用变量名来做表名或者列名. 比方,有一个表我们想以"2015-07 ...
- 免费电子书:The Guide to Minimum Viable Products
本地下载 来自uxPin的免费电子书
- Activity基本跳转
详细解释:http://blog.csdn.net/xiazdong/article/details/7664757 简单介绍activity的跳转,通过intent实现,详细的注释在代码中.涉及到a ...
- ubuntu 安装 codelite
http://www.linuxidc.com/Linux/2013-06/85332.htm Ubuntu 12.04下为codelite增添更新源 1.获取codelite的公钥 sudo apt ...
- PHP表单-PHP $_POST 变量
PHP $_POST 变量 在 PHP 中,预定义的 $_POST 变量用于收集来自 method="post" 的表单中的值. $_POST 变量 预定义的 $_POST 变量用 ...