【问题标题】:HornetQ Consumers on Linux High CPU Load在 Linux 高 CPU 负载上的 HornetQ 消费者
【发布时间】:2013-01-08 15:30:28
【问题描述】:

我们在 CentOS 6.3 上使用 HornetQ 2.2.14。我们在应用服务器中遇到了 CPU 使用率过高的问题,并已使用分析器将其范围缩小到 HornetQ 消费者。

具体来说,我们在大约有 150 个消费者的空队列上快速连续调用此方法:

// Called about every 10ms per consumer.
javax.jms.MessageConsumer.receive(10);

这导致大约 2 个 NIO 工作线程回溯到 Netty,在我们原本空闲的 Tomcat 实例上消耗了大约 2 个 CPU 内核的 50%。

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
21939 tomcat    20   0 9061m 1.6g  16m R 55.4 21.2   1:06.88 java
21777 tomcat    20   0 9061m 1.6g  16m S 47.6 21.2   1:29.40 java
21777 tomcat    20   0 9061m 1.6g  16m S  7.3 21.2   1:33.41 java
21763 tomcat    20   0 9061m 1.6g  16m S  6.6 21.2   1:28.84 java
21682 tomcat    20   0 9061m 1.6g  16m S  4.3 21.2   0:26.70 java

问题是,在 Windows 上使用完全相同的代码和 Tomcat 配置,CPU 内核是空闲的。这让我相信这是一个 Linux/Netty/HornetQ 问题。以前有没有其他人见过这个,如果有,我该如何让它消失?

Linux 版本:CentOS 6.3 x64 Linux内核版本:Linux版本2.6.32-279.19.1.el6.x86_64

这是我测试过的 2 个 Java 版本,结果相同:

Java(TM) SE Runtime Environment (build 1.7.0_10-b18)
Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode)

Java(TM) SE Runtime Environment (build 1.6.0_38-b05)
Java HotSpot(TM) 64-Bit Server VM (build 20.13-b02, mixed mode)

【问题讨论】:

  • 忘了补充,这里是分析器识别的热点:org.hornetq.core.client.impl.ClientConsumerImpl.receive() 和 org.jboss.netty.channel.socket.nio。 SelectorUtil.select()
  • 通过 切换 HornetQ 使用阻塞 IO 没有影响。现在不是 2 个 NIO 工作线程消耗 CPU,而是 2 个阻塞 IO 工作线程消耗相同数量的 CPU。一个客户端线程和一个服务器线程。
  • 如果将超时值增加到 30 毫秒会发生什么。我问是因为如果超时值接近实时时钟的分辨率,可能会发生意外情况,我记得时钟在 10 毫秒左右运行。
  • CPU 使用率似乎与超时值成正比。如果我降低超时时间,或者使用 ClientConsumerImpl.receiveNoWait(),CPU 使用率会上升更多。如果我将超时时间增加到 30 毫秒,CPU 使用率会下降一点,但仍然高于预期。也就是说,它的使用率从 40% 下降到了 20%。
  • 切换 HornetQ 连接和接受器工厂以使用“在 VM 中”而不是 Netty 只是为了进行测试,问题就消失了。这一定是 Linux 上的 Netty 的问题,因为它在 Windows 上运行良好。

标签: java jms netty nio hornetq


【解决方案1】:

虽然 Clebert 的回答有点难以接受,但它最终是一个有效的案例。您可以轻松创建多个消息侦听器,它们将充当您的工作人员并允许 JMS 提供者调用它们。假设您的目的地是某种队列,消息侦听器将以相当分散的负载被调用,以允许多个线程处理处理。创建消息侦听器将允许 JMS 提供者在消息到达时调用它们,而不是等待您的客户端使用消息。

每次调用接收方法时,它都会按照 Clebert 描述的方式运行(他应该知道,他是 HornetQ 的负责人)。

我不确定 Netty HornetQ 2.2.14 是什么版本,但我确实在 github 上的 repos 中发现了一些与非常相似的问题相关的问题。也许您可以尝试在您的应用程序中更新 Netty 的版本,看看是否有帮助?

https://github.com/netty/netty/issues/592

https://github.com/netty/netty/issues/582

【讨论】:

    【解决方案2】:

    IMO 你应该使用 MessageListener.. 或者只是阻塞更长的时间,比如 10 秒...

    ... 10 毫秒重复对您的系统来说是一个巨大的爆发。特别是客户端每次都会向服务器发送回调。

    让消息系统为您完成工作,即在消息到达时让它呼叫您。如果您每 10 毫秒轮询一次系统,那么您将无法期待其他任何事情。

    正如您自己所说,这是您的问题的罪魁祸首:

    consumer.receive(10);
    

    算一算,您使用此 receive(10) 锤击服务器的每个消费者正在使服务器每秒向您发送 100 条消息,每个消费者说...我是空的。

    receive(10) 将进行往返以保证没有消息在传输中。所以,你是在用空消息敲击服务器。

    根据您强制应用的参数,您的应用程序不应该表现良好。对于任何保证在返回 null 之前接收 (10) 为空的消息解决方案。

    【讨论】:

    • 如果是这种情况,为什么相同的代码在所有 CPU 内核都处于空闲状态的 Windows 上运行良好?我希望 HornetQ 能够在不使用大量 CPU 资源的情况下同时处理几百个消费者。
    • 问题不在于 HornetQ,您只是在 10 毫秒内请求一条新消息并且没有完成循环。众所周知,Linux 内核在分配任务方面做得更好,也许更高效的内核让你的坏代码有更多的执行?当然,这只是一个猜测,但您的代码已被破坏......我可以向您保证,这将是任何消息传递提供商的问题。
    • 你正在做的将等同于:while (true) { db.select(0);等待(10); } 你把你的 CPU 浪费归咎于 HornetQ?这会在您实际使用的任何软件上浪费 CPU。不仅仅是消息传递提供程序。
    • 太搞笑了...我给了你一个不好的问题的正确答案,你给了我一个-1 票......无论如何:祝你的无限循环好运。而(真){睡眠(1);什么都不问;您不仅在浪费您的 CPU,而且还浪费了其他人的时间
    • 我对您的答案投了反对票,因为它既不正确,也没有帮助。你对我的用例做了太多疯狂的假设。我从来没有说过我在投票。我实际上有一个用于处理 Web 请求的消费者池。一个请求进来,从池中抓取一个消费者来检查队列。这就是我不能像你建议的那样等待 10 秒的原因。如果队列中没有任何内容,则请求必须几乎立即返回。消息传递系统有 receiveNoWait() 是有原因的。等待消息的时间并不总是可以接受的。
    猜你喜欢
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 2021-05-20
    • 2020-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多