xjjdog之前写过很多关于消息队列的文章。今天给大家介绍一下ActiveMQ。ActiveMQ是最常用、功能最丰富的消息中间件。通常用于消息异步通信、调峰解耦等各种场景,是JMS规范的实现者之一。功能丰富到什么程度?支持大部分消息协议,支持XA。也是一个比较老的消息队列。新版本虽然最近更名为阿耳emi弥斯,但也无法抹去其上的沧桑。这是一个重量级的东西,很多公司都不能丢。下面给大家说说具体的架构设计。也许你应该从人性而非技术的角度来考虑它的存在。以下是正文。一、架构设计概述ActiveMQ提供了两种可以实现的架构模型:“M-S”和“网桥”;其中“M-S”是HA方案,“网络转发桥”用于实现“分布式队列”。1.1.M-SMaster-Slave模型下,通常需要2+个ActiveMQ实例,任何时候只有一个实例是Master,为Client提供“生产”和“消费”服务,Slaves用于备份或等待故障转移。角色接管。M-S模型是最常见的架构模型,它提供了“高可用性”特性。当Master发生故障时,其中一个Slave提升为Master继续提供服务,Failover后仍然可以恢复消息。(根据底层存储,可能会出现消息丢失)。主要有两点:第一,在M-S架构中,说到选举,选举的首要条件是需要“排他锁”的支持。独占锁可以在共享文件锁、JDBC数据库独占锁、JDBC锁租约、zookeeper分布式锁中实现。这取决于底层存储的机制。其次,在M-S架构中,消息存储有多种机制,如“共享文件存储”、“JDBC”存储、“非共享存储”等。不同的存储机制各有优缺点。使用时必须有所取舍。1.2、网络转发桥(networkbridge)在任何情况下,一组M-S所能承载的消息量和客户端并发水平总是有限的。当我们的消息规模达到单机的上限时,我们应该采用基于集群的方式。消息和客户端是分布式和负载平衡的。ActiveMQ提供了一种“网络转发桥接”模式。其核心思想是:1、集群中的多个broker通过“连接”相互通信,在多个broker之间转发和存储消息,并在存储层面提供“load负载”。balanced”。2.根据客户端的并发,动态平衡客户端,最终支持大规模的生产者和消费者。这和Kafka的核心思想类似。2.M-S架构设计详解2.1.有非共享存储模式集群2+个ActiveMQ实例,每个实例独立存储数据,Master将消息保存到本地后,异步转发消息给Slaves,master和slave独立部署,各自负责自己的自己的存储。master和slave通过一个“networkconnector”连接。通常情况下,master与slave建立单向连接。master上收到的所有消息都会完整转发给slave。有如下关键要点:1)任何时候只有Master为Client提供服务,slave只作为备份,旧的shadownode方式。2)slave上存储的消息有短暂的延迟。3)master总是大师。当master失效时,我们不能随意转换角色。最好的实现方式是重启master。只有当master发生物理故障时,slave才会被认为提升为master。(这个真的很弱)4)当slaves需要提升为master时,要保证slaves的消息是最新的。5)如果slaves掉线,在重启slaves之前,需要手动将master的数据同步到slaves。否则slave离线期间的数据不会在slave上重现。6)客户端不支持故障转移协议;也就是说,client只会与master建立连接。这种架构是最原始的架构,容易实时,但是问题比较严重,缺乏Failover机制,我们不能完全保证消息的可靠性,因为没有主从角色切换的仲裁者,或者缺乏分布式排他锁机制。在生产环境中,不推荐使用。如果您可以容忍故障转移期间SLA级别的下降,它也可以用作备选方案。2.2.共享文件存储采用SAN(GFS)技术,一种基于网络的全局共享文件系统模式(真正的排名制造机),这种架构简单易用,但可架构设计能力较弱。在生产环境中酌情使用。SAN存储,请参考GFS。master和slaves配置一致,每个broker需要有唯一的brokerName;broker实例在启动时首先通过SAN获取文件系统的独占锁,获得锁的实例将成为master,其他broker会等待锁并间歇性地从slave不提供Clients服务;因为broker向GFS写入数据,故障转移后,新的master获取的数据视图仍然和原来的master一致。毕竟,GFS是一个全球共享的文件系统。我们通常使用kahaDB作为存储引擎,即日志文件;kahaDB的存储效率非常高,TPS可以高达2W左右。它是一种高效的存储机制,具有强大的数据恢复能力。在这种架构模式下,支持故障转移。当master发生故障时,clients可以通过failover协议与新的master重新连接,服务中断时间非常短。因为是基于GFS存储,数据一直保存在远程共享存储区,不存在数据丢失的问题。唯一的问题是GFS(SAN)的稳定性。这需要确定,SAN区域内节点间的网络通信必须稳定高效。(自己搭建比如NFS服务,或者基于AWSEFS)。这无非是将问题转移到另一个组件上。2.3.基于JDBC共享存储,我们可以使用支持JDBC的数据库作为共享存储层,即master向数据库写入数据,本地不保存任何数据。failover时,slave提升为master后,新的master可以从数据库中读取,也意味着master和slave的数据视图在整个周期内是一致的(同SAN架构),所以数据恢复和一致性可以得到保证,并且没有数据丢失(在存储层)。但是JDBC存储机制的性能太低了。与kahaDB等基于日志的存储层相比,性能相差10倍左右。我的天啊。但是在一些低并发和纯解耦的场景下,是可以的。在高并发的互联网上使用它是找死(互联网并不一定意味着高并发)。如果您的业务需求表明无法容忍数据丢失并且SLA级别非常高,那么JDBC可能是您的最佳选择。由于JDBC数据库是最终的存储层,我们往往需要关注数据库的可用性,比如数据库是基于M-S模式的;如果数据库发生故障,ActiveMQ集群将不可用。JDBC存储面临的最大问题是“TPS”(吞吐量),确实比kahaDB低了好几倍。如果你的业务有高峰,“削峰”策略可以先将消息写入本地文件(然后异步同步到AcitveMQBroker)。这时候我总是有一个疑问。直接用数据库就好了,何必费心用ActiveMQ。也许是为了设计而设计。3、网桥模式架构这种架构模式主要是为了应对大规模Client和高密度消息增量场景;它将以集群模式承载具有大量数据的应用程序。它具有以下要求和特点。1)有大量的Producers和Consumers客户端访问。这样做的唯一原因可能是在横向扩展的方向上拆分消息通道(Topic、Queue)的可能性不大。所以都是挤在一起的。2)也许消息的增量是巨大的,尤其是一些“非持久化消息”。我们希望构建一个“分布式队列”架构。这是其他系统无法解决的问题。希望消息队列能缓冲一下。3)由于集群规模较大,我们可能允许集群的部分节点暂时下线,但仍需提供数据恢复机制。总体而言,集群仍然提供高可用性。4)集群支持Clients的负载均衡。例如,当有多个生产者时,这些生产者将在多个代理之间动态平衡。否则,分配不均会产生风险。5)支持故障转移,即当一个broker发生故障时,Client可以与其他broker重新连接;当新的broker加入集群时,集群的拓扑结构也可以动态通知给Clients。这是运维人员的最爱,没人愿意半夜起来摆弄机器。集群由多个子Group组成,每个子Group都是M-S模式,共享存储;多个Group基于“网络连接器”(主从协议)连接,通常是双向连接,所有Group相互连接,Group之间形成“订阅”关系。比如G2在逻辑上是G1的订阅者(订阅策略是根据各个Broker上consumer的Destination列表分类的),消息转发的原理也是基于此。对于客户端,仍然支持故障转移,故障转移协议可以包括集群中“多数”节点的地址。Topic订阅者的消息将被复制并存储在所有Groups中;来自Queue的消息会在broker之间转发,最终到达Consumer所在的节点。Producers和Consumer可以在任意Group中与Master建立连接,相互通信。当Brokers集群拓扑发生变化或者Producers或Consumers的数量发生变化时,Client的连接位置会动态平衡。Broker使用“咨询”机制来同步Client的连接信息。例如,当有新的Consumer加入时,Broker会发送一个advisory消息(内部通道)通知其他broker。集群模式提供了更好的可用性保障能力,有些特性可能需要折衷。例如,Queue的消息顺序会被打乱,因为同一个Queue的多个消费者可能位于不同的组中。如果是Group实现,则保存在其上的消息将仅在恢复时对Clients可见。4.性能评价综上所述,在Production环境下,我们真正可以采用的架构只有三种:1)基于JDBC的共享数据库模式:HA架构,单个Group,Group包含一个master和任意数量的slave;所有Broker通过远程共享数据库访问数据。客户端支持故障转移协议。2)基于NetworkBridge构建分布式消息集群:集群架构,集群中有多个Group,每个Group为M-S架构,基于共享存储;对于Client,它支持负载均衡和故障转移;消息从Producer出发,到达Broker节点,Broker根据“消费者在集群中的分布”将消息转发给Consumers所在的Broker,实现消息的按需流转。3)基于NetworkBridge的简化改造:与2)类似,但每个“Group”只有一个Broker节点,而这个Broker是基于kahaDB本地文件存储的,即相对于2)Group缺少HA特性;当Broker节点出现故障时,其上的消息将不可见,直到Broker恢复正常。这种简化版本的架构模型通过增加机器数量和细分消息分发来降低数据影响和故障影响的规模。因为是基于kahaDB本地日志存储,所以性能非常高。4.1.分享JDBC测试结果生产端配置。生产者端(压力输出机):数量:4硬件配置:16Core,32G,云主机软件配置:JDK1.8,JVM24G并发和线程:32个并发线程,连接池128个,发送短信,每条短信128个字符实体.Message:持久化、Queue、非事务Broker配置。Broker数量(承压):2硬件配置:16Core,32G,云主机软件配置:JDK1.8,JVM24G架构模式:M-S模式,开启异步转发,关闭FlowControl,数据库连接池配置1024存储层。数据库数量(存储层):2硬件配置:16Core,32G,SSD(IOPS3000),云主机架构模式:M-S数据库:MySQL测试结果:1.消息生产效率:1500TPS2.Brokerload:CPU30%,Memoryusage11%3.MySQLload:CPU46%,IO_WAIT25%结论:1.基于共享JDBC存储架构,性能确实很低。2、影响性能的关键点是数据库的并发IO能力。当TPS在1800左右时,数据库磁盘(包括slave同步IO)已经出现高IO_WAIT。3、通过升级磁盘,提高IOPS,可以有效提升TPS指标。建议同时增加CPU数量。打算用数据库实现HA的同学,你见过这他妈的TPS吗?4.2、基于非共享文件存储的测试结果测试单个ActiveMQ,基于kahaDB存储,kahaDB分为两种数据刷刷模式:1)逐条消息刷2)每秒
