【问题标题】:Amazon MQ (ActiveMQ) bad performance on large messagesAmazon MQ (ActiveMQ) 处理大型消息时性能不佳
【发布时间】:2020-07-06 05:52:24
【问题描述】:

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

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

如果我们将这种大小的 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

如果我们将相同的文件放在 Amazon MQ(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 毫秒),但非常发送速度慢。

在 Amazon MQ 上,我们使用 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 区域伦敦,一项来自 AWS 法兰克福区域,位于不同的 VPC 中,1 项来自法兰克福,位于与 Amazon MQ 代理相同的 VPC 和同一子网中。所有客户端都在 EC2 实例上运行:m4.xlarge。

如果我们仅使用一个 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

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

也许有人可以告诉我哪里出了问题,为什么我们在使用 Amazon MQ 或 ActiveMQ 时表现如此糟糕?

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

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

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

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

我删除了连接池并设置了 concurrentStoreAndDispatchQueues="false" 我使用的系统代理:mq.m5.2xlarge 和客户端: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 实现。

我认为 Amazon MQ 可能是小文件的解决方案,但对于大文件却不是。我认为我们必须在这种情况下使用 IBM MQ,它具有更好的性能。但有一件重要的事情:我只在我们的 LAN 中测试了 IBM MQ。我们尝试在 Amazon 上测试 IBM MQ,但尚未成功。

【问题讨论】:

  • 这是一个非常好的问题,能否请您详细说明您对它进行基准测试的方式(测量什么?测量时间的开始和结束时间?这些平均时间是一条消息还是整个消息?批处理?),以及 IBM MQ 实例位于何处?它在您的本地网络中吗?此外,在您的测试中,您是在发送的每个文件上打开一个连接,还是在同一连接中推送/拉取 300 个文件?抱歉,我要求进行大量改进,但如果您使用这些详细信息更新您的问题,将会很有帮助。
  • 感谢 Anton 的回复,我已经更新了回答您问题的请求

标签: jms activemq amazon-mq


【解决方案1】:

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

我必须进一步调查 ActiveMQ 的性能,然后才能确定导致此问题的确切原因。

【讨论】:

    【解决方案2】:

    我试图重现您正在测试的场景。当我在与具有活动和备用实例的 mq.m5.4xlarge 代理的 AmazonMQ 代理相同的 VPC 中运行 JMS 客户端时,我看到以下往返延迟 - 测量从生产者发送消息的时刻到消费者发送消息的时刻收到消息。

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

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

    在ActiveMQ中,有Fast Producer和Fast Consumer的概念,也就是说,如果consumer能够以与Producer相同的速率处理消息,则broker将消息从producer通过内存传递给consumer,然后写入消息到磁盘。这是默认行为,由名为 concurrentStoreAndDispatch 的代理配置设置控制,该设置为 true(默认)

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

    ActiveMQ 提供advisory topics,您可以订阅它以检测慢速消费者。如果实际上您检测到消费者比生产者慢,最好将 concurrentStoreAndDispatch 标志设置为 false 以获得更好的性能。

    【讨论】:

    • 嗨,山姆,非常感谢您的回复。请参阅上面的问题,我会回复您的回答。
    • Ben,这些消息的最小延迟预期是多少?一种替代方法是将大型消息上传到 S3 并将 S3 指针放在 Amazon MQ 队列上。当消费者拿起消息时,获取 S3 指针并从 S3 获取消息。
    • 您好 Sam thx,我们聘请了一家外部公司,并与 AWS 工程师一起为我们提供了下一步建议,他们将评估我的测试。
    猜你喜欢
    • 2021-05-08
    • 2019-06-02
    • 2019-07-26
    • 2010-10-16
    • 2019-10-09
    • 2015-09-09
    • 2016-04-14
    • 1970-01-01
    • 2014-09-24
    相关资源
    最近更新 更多