RabbitMQ双活架构设计.docx
- 文档编号:12111773
- 上传时间:2023-04-17
- 格式:DOCX
- 页数:14
- 大小:656.17KB
RabbitMQ双活架构设计.docx
《RabbitMQ双活架构设计.docx》由会员分享,可在线阅读,更多相关《RabbitMQ双活架构设计.docx(14页珍藏版)》请在冰豆网上搜索。
RabbitMQ双活架构设计
RabbitMQ双活架构设计
消息服务中间件在日常工作中用途很多,如业务之间的解耦,其中RabbitMQ是比较容易上手且企业使用比较广泛的一种,本文主要介绍有货在使用RabbitMQ的一些实践与尝试。
有货的RabbitMQ部署架构采用双中心模式,在两套数据中心中各部署一套RabbitMQ集群,各中心的RabbitMQ服务除了需要为业务提供正常的消息服务外,中心之间还需要实现部分队列消息共享。
消息传递的可靠性
场景1:
生产者与消费者互不感知,怎么确认生产者已将消息投递到RabbitMQ服务端,又如何确认消费者已经消费了该消息?
消息Publish可靠性
首先来谈谈Publisher的可靠发送,如果使用标准AMQP0-9-1,保证消息不丢失的唯一方法是使用事务,但使用事务模式会导致服务端吞吐量急剧下降。
为了弥补这一点,AMQP引入了确认机制。
它模仿了协议中已经存在的消费者ACK确认机制。
Publisher通过发送confirm.select命令开启确认模式,随后RabbitMQ服务端在收到消息后会进行确认,Publisher会收到服务端发送的确认回复。
要注意:
无法在通道中同时使用确认模式与事务模式,只可二选一。
消息Consume可靠性
再说说如何保证队列中消息至少被消费一次。
当RabbitMQ交付消息给Consumer时,需要确认Message已被投递到Consumer。
Acknowledgements作用,Consumer发送确认消息通知RabbitMQ服务端已收到消息或已成功消费消息。
看下消息生产、消费的流程图:
在1号的位置需要开启Channel的Confirm模式,接收RabbitMQ服务端发送的确认消息已到达的Ack信息;在3号的位置,消费者在成功消费或者业务处理失败后,需要告诉RabbitMQ服务端,消息已被消费成功或者失败;当然在某些网络故障中,数据包丢失可能意味着中断的TCP连接需要较长时间才能够被操作系统检测到。
通过心跳功能,确保应用程序层及时发现连接中断。
在我们的部署架构中,ELB与RabbitMQ之间就是通过此机制来判断服务是否存活,通知消息生产者服务端已挂,异步等待Confirm的消息直接进入Unconfirm的处理环节。
另外为了避免在代理中丢失消息,AMQP标准具有交换、队列和持久消息的耐久性概念,要求持久对象或持久消息将在重新启动后生存,这些特性同样也是可靠性的基础。
实现消息的延迟重试机制(重试队列)
场景2:
在某些情况下,业务系统在处理消息时可能会失败,此时需要做的是重试,而不是直接丢弃;当然重试也不能直接重试,一旦有任务长时间失败,会导致后面的消息无法被正常处理,此时可以借助死信机制(消息在队列中存活时间超出队列ttl的设定)转发投递到特定的重试队列后,随后再尝试重新处理该消息。
下面介绍具体操作:
首先创建两个队列,工作队列命名为“yoho_test_retry”,重试队列命名为“yoho_test_retry.retry“。
再看下工作队列的参数配置:
∙x-dead-letter-exchange:
死信转发的Exchange
∙x-dead-letter-routing-key:
死信转发时的Routing-key
∙yoho_test_retry绑定到名为“amp.topic”的topic类型Exchange,接收Routing-key为“yoho_test_retry”的消息
再看下重试队列的参数配置:
∙死信转发到“amp.topic”的Exchange
∙Routing-key为“yoho_test_retry”(即工作队列yoho_test_retry接收该主题消息)
∙x-message-ttl:
message在重试队列中存活的时间,也就是延迟多久重试。
该队列绑定到“amp.topic”的Exchange,接收Routing-key为“retry.yoho_test_retry”的消息(即接收工作队列的死信),这样就可以实现消息重试队列的机制了
当然还有别的方式,如通过声明Retry的Exchange来中转到Retry队列中,不需要指定x-dead-letter-routing-key,再指定Retry队列的dead-letter-exchange为“amp.topic”即可,这种方式不需要每个队列都生成一个Retry队列,大家可以自己动手尝试下。
实现消息的延时消费(延时队列)
场景3:
如何实现消息的延时消费也是一种常见的需求,可以让某些任务延时执行,其实同样也可以借助死信机制来实现。
队列A用于接收暂存Producer的消息,队列B用于Consumer的消费,在队列A中指定消息的ttl即生命周期时长,同时指定其死信交换机DLXs,一旦消息在队列中存活时长超过ttl的设定值,那么消息会被转发到DLXs,将队列B绑定到DLXs,即可接收到队列A的死信。
具体操作流程,与场景2一样,首先创建两个队列:
工作队列名为“yoho_test_delay”,延迟队列名为“yoho_test_delay.delay“。
再看下工作队列的配置参数:
∙从“amp.topic”的Exchange中接收Routing-key为“delay.yoho_test_delay”的消息。
延迟队列“yoho_test_delay.delay”的配置:
∙x-dead-letter-exchange死信转到交换机“amp.topic”
∙死信消息的Routing-key为“delay.yoho_test_delay”(即工作队列接收消息的Routing-key)
∙消息在延迟队列中存活时间ttl
∙该队列绑定到“amp.topic”交换机,接收Routing-key为“yoho_test_delay”的消息(即生产者发送消息指定的topic)。
如此一来延迟队列接收消息后,等待ttl时长后将消息转发到工作队列中,即可实现延迟队列机制
同样还有别的方法,大家可以灵活实现。
实现跨数据中心的消息共享
场景4:
有时跨中心业务需要共享消息,如缓存清理等,在业务代码中分别向多个中心的RabbitMQ发布消费消息显然不是一种比较好的解决方案,那还有什么好的方法呢?
RabbitMQ为此提供了Federation插件来很好地解决此类问题,有货跨中心部署Federation架构图:
Federation插件是一个不需要构建Cluster,而在Brokers之间传输消息的高性能插件,Federation插件可以在Brokers或者Cluster之间传输消息,连接的双方可以使用不同的users和virtualhosts,双方也可以使用版本不同的RabbitMQ和Erlang。
Federation插件使用AMQP协议通讯,可以接受不连续的传输。
FederationExchanges,可以看成Downstream从Upstream主动拉取消息,但并不是拉取所有消息,必须是在Downstream上已经明确定义Bindings关系的Exchange,也就是有实际的物理Queue来接收消息,才会从Upstream拉取消息到Downstream。
使用AMQP协议实施代理间通信,Downstream会将绑定关系组合在一起,绑定/解除绑定命令将发送到Upstream交换机。
因此,FederationExchange只接收具有订阅的消息,本处贴出官方图来说明;
但是注意,由于绑定是异步发送的Upstream的,所以添加或删除绑定的效果并不立即生效,消息被缓冲在Upstream交换机的所在Broker创建的队列中,这被称为Upstream队列。
任何UpstreamExchange接收到的消息都可能被Downstream中FederationExchange接收到,但直接发送给FederationExchange的消息是不能被Upstream中所绑定的Exchange接收到的。
下面动手创建名为“fed_test”的FederationExchange,配置Federation策略“fed_ex”,Federation-upstream-set可以简单的配置为“all”,表示与所有的Upstream都建立点对点的Federation连接。
此时在Downstream上可以看到建立了一个Running-Links连接到Upstream,该Exchange就可以收到Upstream中同名Exchange收到的所有消息(前提是Downstream中有物理队列接收)。
大家应该都知道RabbitMQ中单Queue能够对外提供的服务能力有局限性,如何通过Federation来满足跨中心同时高并发的场景呢,此时就需要自己编写插件了,结合后面会介绍的Sharding分片机制,创建多个Federation缓冲队列分摊压力,本人的想法仅供参考。
实现消息队列的高可用(HA容灾)
场景5:
需要保证消息队列高可用的场景有很多,比如核心业务的订单服务、erp服务。
默认情况下,RabbitMQ群集中的队列位于单个节点上(首次被声明的节点上),而Exchanges和Bindings可以认为在所有节点上存在,但也可以将Queue在Cluster节点之间配置为镜像队列。
每个镜像队列由一个Master和一个或多个Slave组成,如果Master因为某些原因失效,则将从Slave中选择一个提升为Master。
发布到队列的消息将复制到所有镜像,消费者连接到主机,无论它们连接到哪个节点,镜像会丢弃已在主设备上确认的消息,队列镜像因此增强了可用性,但不跨节点分配负载。
如上图创建名为“ha_test_queue”的队列,同时为该队列配置了策略Policy,Ha-mode简单配置为all,当然可以使用Ha-node参数选择节点制作镜像。
此时队列已被配置为镜像,master节点位于server5,slave节点位于server6,此时,随意关闭任意一台RabbitMQ节点,该队列都可以正常对外提供服务。
当然在高可用的场景下,队列的性能会受到一定的影响,此时可以借助后面提到的Sharding机制(根据场景选择x-modulus-hash还是consistent-hash),解决单队列的性能瓶颈,在高可用、高并发下寻求一个动态的平衡。
RabbitMQ分片机制
在解决RabbitMQ单Queue性能问题时可以用到RabbitMQSharding插件,该插件可以提供消息的自动分片能力:
自动创建分片队列,同时交换机将在队列中分区或分片消息。
在某些情况下,你可能希望发送到交换机的消息一致并且均匀地分布在多个不同的队列。
在上面的插件中如果队列数量发生变化,则不能确保新的拓扑结构仍然在不同队列之间均匀分配消息,此时就可以借助Consistent-sharding类型Exchange,与Sharding插件的主要区别是,该类Exchange不能自动创建分片队列,需要手动创建并配置Binding关系,且支持一致性hash。
RabbitMQ高并发实践
衡量消息服务的性能最重要的指标之一就是吞吐量,那RabbitMQ的高并发到底可以到多少呢?
首先使用了32台8核30G内存的虚拟机,构建了相对来说比较庞大的RabbitMQ集群,各虚拟机的作用分配如下:
∙30RabbitMQRAM节点(正常RAM节点,RabbitMQ元数据和定义仅保存在RAM中);
∙1RabbitMQDisc节点(元数据持久化节点,其中RabbitMQ代理元数据和定义也保留在光盘上);
∙1RabbitMQStats节点(统计信息节点,运行RabbitMQ管理插件,不带任何队列)。
测试环境架构结构图,大致如下:
在RabbitMQ群集节点的前面,挂载负载均衡器,负载均衡器配置中包含了除统计信息节点以外的所有节点。
来自连接的AMQP客户端的请求在目标池中的节点之间进行了平衡。
从目标池排除统计信息节点有助于确保消息队列和传送工作不会最终与管理节点发生资源竞争。
在较低吞吐量的情况下,用户可以选择将统计信息节点包含在负载平衡器后台服务池中。
实验结果如下:
在这种高负载的生产(1345531msgs/pers)消费(1413840msgs/pers)压力下,RabbitMQ仅有2343条消息暂时在其等待发送的队列中累积,在这样的负载下,RabbitMQ节点也没有显示内存压力,或者需要基于资源限制启动流控机制。
我们在AWS上搭建了同等规模与配置的环境,验证了上述Google提供的测试方案及结果后又做了一些别的尝试,如使用RabbitMQSharding插件、Consistent-hashShardingExchange来更加灵活地动态均衡队列压力,可以更从容地达到百万并发的性能。
高可靠与高可用从来都是性能杀手,那RabbitMQ的表现如何,实际生产应用中应该中如何做权衡?
最后通过一组数据来说明,RabbitMQ环境配置:
∙单虚拟机:
8C8G;
∙单位消息大小:
1KB;
∙压测工具:
rabbitmq-perf-tes(官方提供)。
上图中,我们在单节点RabbitMQ上对消息持久化、Consume-Ack、Publish-Confirm三个特性做了压测,消息持久化对性能影响最大,Consum-Ack其次,Publish-Confirm最小。
Prefetch,可以理解为Consumer一次最多获取多少消息进行消费,可以看到,当Prefetch为10时,性能最差,当Prefetch放大到一定阈值如10000,其对性能的影响也就微乎其微了。
再考虑下,多消费者多生产者对性能的影响,如上图适当增加消费者,保持队列的空闲,可以增加吞吐量,但当到达某一瓶颈时,效果不太明显了。
在集群场景下,Ack对性能影响明显。
上图为镜像场景的压测结果,对比普通集群,镜像对性能的影响很明显,消息持久化也拉低了集群的性能,适当增加Prefetch可以提高集群性能。
性能与高可靠、高可用,鱼和熊掌不可兼得,所以想提升RabbitMQ集群或单节点服务的性能,可以牺牲可靠性(根据场景来),在消费能力范围内,尽量提高Prefetch的数量;其次就是简单粗暴型(加机器加配置,队列实际存储节点性能未榨干,建议队列均衡分配到各节点)。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- RabbitMQ 架构 设计