AmazonMQ(ActiveMQ)在大型消息上的性能不佳



我们正在从IBM MQ迁移到Amazon MQ,至少我们希望这样做。问题是,与IBM MQ相比,使用JMS生产者将大消息放入队列时,Amazon MQ的性能较差。

所有消息都是持久的,系统对于IBM MQ是高可用的,而Amazon MQ是多AZ的。

如果我们将这种大小的XML文件放在IBM MQ(2 cpu和8GB RAM HA实例)中,我们将具有以下性能:

256 KB = 15ms
4,6 MB = 125ms
9,3 MB = 141ms 
18,7 MB = 218ms
37,4 MB = 628ms
74,8 MB = 1463ms

如果我们将相同的文件放在AmazonMQ(MQ.m5.2xlarge=8 CPU和32 GB RAM)或ActiveMQ上,我们就有这样的性能:

256 KB = 967ms
4,6 MB = 1024ms
9,3 MB = 1828ms 
18,7 MB = 3550ms
37,4 MB = 8900ms
74,8 MB = 14405ms

我们还看到,IBM MQ向队列发送消息和从队列获取消息的响应时间相等,而Amazon MQ获取消息的速度非常快(例如,只需1毫秒),但发送速度非常慢。

在AmazonMQ上,我们使用OpenWire协议。我们在Terraform风格中使用此配置:

resource "aws_mq_broker" "default" {
broker_name                = "bernardamazonmqtest"
deployment_mode            = "ACTIVE_STANDBY_MULTI_AZ"
engine_type                = "ActiveMQ
engine_version             =  "5.15.10"
host_instance_type         =  "mq.m5.2xlarge"
auto_minor_version_upgrade =  "false"
apply_immediately          =  "false"
publicly_accessible        =  "false"
security_groups            = [aws_security_group.pittensbSG-allow-mq-external.id]
subnet_ids                 = [aws_subnet.pittensbSN-public-1.id, aws_subnet.pittensbSN-public-3.id]
logs {
general = "true"
audit   = "true"
}

我们通过POM(Maven)将Java 8与JMS ActiveMQ库一起使用:

<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>5.15.8</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>5.15.8</version>
</dependency>

在JMS中,我们有以下Java代码:

private ActiveMQConnectionFactory mqConnectionFactory;
private PooledConnectionFactory mqPooledConnectionFactory;
private Connection connection;
private Session session;
private MessageProducer producer;
private TextMessage textMessage;
private Queue queue;
this.mqConnectionFactory = new ActiveMQConnectionFactory();
this.mqPooledConnectionFactory = new PooledConnectionFactory();
this.mqPooledConnectionFactory.setConnectionFactory(this.mqConnectionFactory);
this.mqConnectionFactory.setBrokerURL("ssl://tag-1.mq.eu-west-1.amazonaws.com:61617");
this.mqPooledConnectionFactory.setMaxConnections(10);
this.connection = mqPooledConnectionFactory.createConnection());
this.connection.start();
this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
this.session.createQueue("ExampleQueue");
this.producer = this.session.createProducer(this.queue);
long startTimeSchrijf = 0;
startTimeWrite= System.currentTimeMillis();
producer.send("XMLFile.xml");  // here we send the files
logger.debug("EXPORTTIJD_PUT - Put to queue takes: " + (System.currentTimeMillis() - startTimeWrite));
// close session, producer and connection after 10 cycles

我们还作为单实例AmazonMQ运行了性能测试。但结果是一样的。我们还使用mq.m5.4xlarge(16 cpu,96 GB RAM)引擎进行了性能测试,但仍然没有改善糟糕的性能。

性能测试配置:我们首先根据上面的内容将消息(XML文件)逐个推送到队列中。我们这样做了5次。5次之后,我们从队列中读取这些消息(XML文件)。我们称之为1循环。

我们一个接一个地运行10个循环,所以我们总共将300个文件推送到队列中,并从队列中获取了300个文件。

我们并行运行了3个测试:一个来自AWS Region Londen,一个来自不同VPC中的AWS Region Frankfurt,还有一个来自法兰克福,与Amazon MQ broker在同一VPC中,在同一子网中。所有客户端都在EC2实例上运行:m4.xlarg.

如果我们只使用一个VPC运行测试,例如只使用与AmazonMQ代理位于同一子网中的本地VPC,则性能会提高,我们会得到以下结果:

256 KB = 72ms
4,6 MB = 381ms
9,3 MB = 980ms 
18,7 MB = 2117ms
37,4 MB = 3985ms
74,8 MB = 7781ms

客户端和服务器在同一个子网中,因此我们与防火墙等无关。

也许有人可以告诉我哪里出了问题,为什么我们的AmazonMQ或ActiveMQ性能如此糟糕?

额外信息:响应时间是在JMS Java应用程序中测量的,Java开始时间刚好在producer.send('XML')之前,结束时间刚好在生产者.send('XML')之后。差异是记录的时间。次数是指超过300个电话的平均次数
IBM MQ服务器位于我们的数据中心,客户端应用程序在同一数据中心的服务器上运行。

额外信息测试:jms应用程序启动创建connectionFactory队列会话。然后它将文件上传到MQ 1 by 1。这是一个循环,然后它在for-lus中运行这个循环10次,而不打开或关闭会话队列或connectionfactorys。然后从队列中读取所有60条消息,并将其写入本地驱动器上的文件。然后它关闭连接工厂和会话以及生产者/消费者。这是一批。然后我们运行5个批次。因此,在批处理之间,会重新创建connectionFactory、队列和会话。

针对Sam:当我也像Sam一样用相同大小的文件执行测试时,我接近相同的响应时间,我将持久性模式也设置为():之间的假值

500 KB = 30ms (6ms)
1 MB = 50ms (13ms)
2 MB = 100ms (24ms)

我删除了连接池并设置concurrentStoreAndDispatchQueues="false"我使用的系统是broker:mq.m5.2xlarge和client:m4.xlarge。

但如果我用更大的文件进行测试,这是响应时间:

256 KB = 72ms
4,6 MB = 381ms
9,3 MB = 980ms 
18,7 MB = 2117ms
37,4 MB = 3985ms
74,8 MB = 7781ms

我有一个非常简单的要求。我有一个系统,它将消息放入队列,消息由另一个系统从队列中获取,有时同时获取,有时不获取,有时在卸载之前系统上有20或30条消息。这就是为什么我需要一个队列和消息必须是持久的,并且它必须是Java JMS实现。

我认为AmazonMQ可能是小文件的解决方案,但对于大文件则不然。我认为在这种情况下,我们必须使用性能更好的IBMMQ。但有一件重要的事情:我只是在局域网中对IBMMQ进行了初步测试。我们试图在亚马逊上测试IBMMQ,但没有成功。

我试图重现您正在测试的场景。当我在与AmazonMQ broker相同的VPC中为mq.m5.4xlarge broker运行JMS客户端时,我看到了以下往返延迟-测量生产者发送消息的时刻到消费者接收消息的时刻。

2MB - 50ms
1MB - 31ms
500KB - 15ms

我的代码刚刚创建了一个连接和一个会话。我没有使用PooledConnectionFactory(事实上说明了这一点,而不是说/怀疑这是原因)。此外,最好将代码精简到最低限度,以便在进行性能测试时建立基线并消除噪声。这样,当您引入额外的代码时,您可以很容易地看到新代码是否引入了性能问题。我使用了默认的代理配置。

在ActiveMQ中,有一个快速生产者和快速消费者的概念,这意味着,如果消费者可以以与生产者相同的速率处理消息,则代理通过内存将消息从生产者传输到消费者,然后将消息写入磁盘。这是默认行为,由名为concurrentStoreAndDispatch的代理配置设置控制,该设置为true(默认)

如果消费者无法跟上生产者的步伐,从而成为"慢"消费者,并且concurrentStoreAndDispatch标志设置为true,那么性能就会受到影响。

ActiveMQ提供咨询主题,您可以订阅这些主题来检测慢速使用者。事实上,如果您检测到使用者比生产者慢,那么最好将concurrentStoreAndDispatch标志设置为false以获得更好的性能。

我没有得到任何响应。我认为这是因为这个性能问题没有解决方案。AmazonMQ是一个云服务,也许这就是性能如此糟糕的原因。IBMMQ是一种不同的体系结构,它是在内部部署的。

我必须对ActiveMQ的性能进行更多的研究,然后才能知道这个问题的确切原因。

最新更新