RabbitMQ HA初步分析

上传人:飞*** 文档编号:29222096 上传时间:2018-01-23 格式:DOCX 页数:5 大小:161.44KB
返回 下载 相关 举报
RabbitMQ HA初步分析_第1页
第1页 / 共5页
RabbitMQ HA初步分析_第2页
第2页 / 共5页
RabbitMQ HA初步分析_第3页
第3页 / 共5页
RabbitMQ HA初步分析_第4页
第4页 / 共5页
RabbitMQ HA初步分析_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《RabbitMQ HA初步分析》由会员分享,可在线阅读,更多相关《RabbitMQ HA初步分析(5页珍藏版)》请在金锄头文库上搜索。

1、RabbitMQ HA 初步分析普通 MQ 的结构X AmqqueueBacking queuebindingMQinoutRabbitmq 大体上可以分为两部分(Exchange 和 MQ),所有发送给 RabbitMQ 的消息都会先交给Exchange, Exchange 的功能类似于路由器,它会根据自身类型(fanout、direct、topic)以及binding 信息决定一个消息该被放到哪一个 MQ, 而 MQ 的功能在于暂时存储消息,并将 MQ 中的消息以订阅或者 poll 的方式交给接收方。MQ 内部大致又可以分为两部分:amqueue 和 backing queue, amqq

2、ueue 负责实现 amqp 协议规定的mq 的基本逻辑,backing queue 则实现消息的存储,它会尽量为 durable=true 的消息做持久化的存储,而在内存不足时将一部分消息放入 DISK 换取更多的内存空间。 Backing queu 内部又细分为5 各小 Q,Q1 Q2 delta Q3 Q4消息在这些 Q 中传递的“一般”过程 q1-q2-delta-q3-q4,这几个 Q 实现的是“RAM -DISK-RAM”这一过程中对消息的分类管理。大多数情况下,一个消息并非需要走完每个小 Q,通常大部分都可以略过。与这 5 各 Q 对应,在 backing queue 中消息的生

3、命周期可以分为四个状态:Alpha:该消息的位置信息和消息本身都在 RAM 中,这类消息排列在 Q1 和 Q4。Beta:消息的位置保存在 RAM 中,消息本身保存在 DISK 中,这类消息排列在 Q2 或 Q3 中。Gamma: 消息的位置保存 RAM 和 DISK 中,消息本身保存在 DISK 中,这类消息排列在 Q2 或 Q3 中。Delta:消息的位置和消息本身都保存在 DISK 中,这类消息排列在 delta 中。从 Q1-Q2-delta 这一个过程是将消息逐步从 RAM 移动到 DISK 的过程,而 delta-Q3-Q4 是从DISK 逐步移动到 RAM 的过程。通常在负载正常

4、时,一个消息不会经历每种状态,如果消息被消费的速度不小于接收新消息的速度,对于不需要保证可靠不丢的消息极可能只会有 Alpha 状态。对于 durable=true 的消息,它一定会进入 gamma,若开启 publish confirm,只有到了这个阶段才会确认该消息已经被接收,若消息消费的速度足够快,内存也充足,这些消息也不会继续走到下一状态。从上述 backing queue 对消息的处理过程可以看出,消息若能尽早被消费掉即在不要走完这 5 个队列,尽量在 q1 或 q2 中就被消费掉,就能减少系统的开销。若走的“太深”则会有内存的换入换出增加系统开销。这样就存在一个问题:通常在系统负载

5、较高时,已接收到的消息若不能很快的被消费掉,这些消息就会进入到很深的队列中去,增加处理每个消息的平均开销。因为要花更多的时间和资源处理“积压”的消息,所以用于处理新来的消息的能力就会降低,使得后来的消息又被积压进入很深的队列,继续加大处理每个消息的平均开销,这样情况就会越来越恶化,使得系统的处理能力大大降低。根据官方博客,应对这一问题,有三个措施:1. 进行流量控制。2. 增加 prefetch 的值,即一次发送多个消息给接收者,加快消息被消费掉的速度。3. 才有 mutli ack,降低处理 ack 带来的开销。目前 RabbitMQ 已经有了很好的流量控制机制,通过前面多次的测试,在测试过

6、程中观察到的现象是,MQ 中堆积的消息数一直都很少(低于 5 个)。需要使用者做的就是 2,3 两点。镜像 MQ 的结构A m q q u e u eR a b b i t _ m i r r o r _ q u q u e _ m a s t e rB Q = v qR a b b i t _ m i r r o r _ q u q u e _ s l a v eB Q = v qR a b b i t _ m i r r o r _ q u q u e _ s l a v eB Q = v qc o o r d i n a t o rG M G M G MA m q q u e u e A

7、 m q q u e u ep u b l i s h e r s c o n s u m e r smirror queue 基本上就是一个特殊的 backing queue, 它内部包裹了一个普通的 backing queue 做本地的消息持久化处理,在此基础上增加了将消息和 ack 复制到所有镜像的功能。所有对rabbit_mirror_queue_master 的操作,会通过组播 GM(Guarenteed Multicast)的方式同步到各slave 节点。新节点加入允许新的 slave 节点中途加入到集群中,新加入的 slave 节点并不同步 master 节点的所有在该slave

8、 加入之前存在的消息,只对新来的消息保持同步,随着旧的消息被消费,经过一段时间后,slave 节点就会与 master 节点完全同步。节点失效当 master 节点失效后,所有 slave 中消息队列最长者会成为新的 master,因为这样的节点最有可能与原来的 master 节点完全同步。节点重启当一个节点无论 master 还是 slave 失效后重启,都会丢弃本地记录在 disk 中的所有消息,作为一个全新的 slave 节点加入到集群中去。GMGM 模块实现的一种可靠的组播通讯协议,该协议能够保证组播消息的原子性,即保证组中活着的节点要么都收到消息要么都收不到。它的实现大致如下:一个组

9、的所有成员组成一个 ring,例如 A-B-C-D-A。假如 A 是 master 节点,A 要发组播消息,A 首先会将消息发送到 A 的后继节点 B,B 接收到消息后在传递给 C 然后是 D,最后 D 再发给 A。在此过程中若有节点失效,发送节点就会往失效的节点的后继节点发消息,若后继节点也失效就往后继的后继发消息。当 A 收到传回来的消息时,A 就可以确认所有 “活着的”节点都已收到该消息,但此时 B、C、D 并不能确认所有节点都收到了该消息,所以不能往上提交该消息。这时,A 往 B 发 Ack,当 B 收到 ack 后就能确认所有的节点都收到该消息, B 将该 ack 继续传递给 C,D

10、最终又传回 A,至此整个发送过程就完成了。若最终 A 没有收到 ack,则说明此次发送失败。使用 RabbitMQ HA 存在的问题及可能的解决方法(1) 在 master 节点失效时,slave 节点可能并未与 mater 节点完全同步造成消息丢失。首先定位到 rabbit_mirror_queue_master 中消息的处理的入口函数publish(Msg = #basic_message id = MsgId , MsgProps, ChPid,State = #state gm = GM,seen_status = SS,backing_queue = BQ,backing_queue

11、_state = BQS ) -false = dict:is_key(MsgId, SS), % ASSERTIONok = gm:broadcast(GM, publish, false, ChPid, MsgProps, Msg),BQS1 = BQ:publish(Msg, MsgProps, ChPid, BQS),ensure_monitoring(ChPid, State #state backing_queue_state = BQS1 ).第一句 Gm:broadcast 做的是将新消息组播到所有 slave 节点,第二句 BQ:publish 的功能是做本地持久化的处理,这

12、里 BQ 是普通的 BQ。对于 durable=true 的消息,只有当消息持久化成功后即进入 gamma 阶段才会向 sender 发确认。所以新消息的处理过程大致可以归纳为:a. 向所有 slave 节点发送该消息b. 持久化c. 发送 ack 给 sender根据 gm.erl 中对 broadcast 的描述“This is a cast and the function call will return immediately. There is no guarantee that the message will reach any member of the group.”该函数

13、是异步的,所以就有可能出现 slave 并未接收到该消息,此时又像 sender 发了确认,接着 master 失效,这条消息就丢失了。解决这个问题的可以采用同步组播方式向所有 slave 节点发消息,即确认所有的 slave都已收到了该消息才向 sender 确认。目前 gm.erl 代码中已经提供了同步发消息的函数gm:confirmed_broadcast/2。从前面对 gm 算法的描述可以看出,这样做的坏处是会增加处理延时,slave 越多,时延越大。(2) 在 mater 节点失效时, ack 消息可能并未同步到所有节点,造成消息的重复发送。为保证消息不丢,接收者在收到消息后,需要向 MQ 回 ack,MQ 收到 ack 后才会删除该消息。但由于 ack 的发送是异步的,将该 ack 消息组播到每个 slave 节点也是异步的,所以在 mater 节点失效时, ack 消息可能并未同步到所有节点,造成消息的重复发送。为解决这一问题,初步有两种思路:第一种,去重。第二种,更改接收者回 ack 的逻辑,改为同步的发送,保证所有的节点都以收到该 ack,才算 ack 成功。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 商业/管理/HR > 其它文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号