【问题标题】:How can I improve performance for an MQ based batch application?如何提高基于 MQ 的批处理应用程序的性能?
【发布时间】:2011-09-07 20:37:41
【问题描述】:

我有一个应用程序,其中消息以每小时 70K XML 的速度持续发送。我们使用这些 XML 消息并将其存储到中间队列中。创建中间队列是因为我们需要满足 24 小时消费所有消息的 SLA。我们能够在 24 小时内使用 XMLS 并将其加载到内部队列中。将其加载到内部队列后,我们处理 XMLS(解析、应用很少的转换、执行很少的验证)并将数据存储到高度规范化的数据模型中。我知道数据模型会对性能产生巨大影响,不幸的是,我们无法控制数据模型。目前,我们需要 3.5 分钟来处理 2K 条消息,这是不可接受的。我们希望将 2K 消息的时间缩短到 1 分钟。以下是我们迄今为止所做的:

1) 在适用的情况下应用索引。
2) 使用 XMLBeans 解析 XML(每个 XML 的大小不是很大)
3) 删除了所有不必要的验证、转换等。

应用程序运行于:
操作系统:RHEL 5.4 64位
平台:JDK 1.6.0_17,64 位
数据库:Oracle 11g R2 64 位(2 节点集群)
外部 MQ:IBM 队列
内部临时存储 MQ:JBoss MQ
应用服务器:Jboss 5.1.0.GA(EAP版)

我们消费和处理 XML 消息的顺序非常重要,因此我们不能进行并行处理。

我们还能做些什么来提高性能?

【问题讨论】:

    标签: xml performance jboss ibm-mq mq


    【解决方案1】:

    WebSphere MQ,即使在小型服务器上,卸载消息的速度也比您描述的快得多。 Windows Performance Report for WMQ V7 在客户端通道上以每秒超过 2,200 次 2k 持续往返(一个请求和一个回复)进行测试。那是每秒 4,000 多条消息。

    在您的情况下,瓶颈似乎是处理消息的延迟以及对以特定顺序处理消息的依赖性。可以为您提供 MOST 性能提升的选项是消除订单依赖性。当我在一家银行工作时,我们有一个系统可以按照交易到达的确切顺序发布交易,每个人都说这个要求是强制性的。但是,我们最终修改了系统,以便在白天发布备忘录,然后在稍后的步骤中重新发布。备忘录发布以任何顺序发生,并支持并行性、故障转移和多实例处理的所有其他好处。一旦它们都在数据库中,最后一篇文章以逻辑顺序(实际上是对客户最有利的顺序)应用事务。序列依赖性将您锁定在单例模型中,并且是异步消息传递的最坏情况要求。尽可能消除它们。

    另一个需要改进的领域是消息的解析和处理。只要您被序列依赖所困扰,这是提高性能的最佳选择。

    最后,您始终可以选择以更多内存、CPU、更快的磁盘 I/O 等形式来解决问题。本质上,这是用马力解决软件架构问题,从来都不是最好的解决方案,但它通常可以为您争取足够的时间来解决根本原因。

    【讨论】:

    • 如您所说,MQ Websphere 的性能相当不错。您提到的问题在尝试处理消息时发生。目前,我们没有重新发布消息的奢侈,所以我们只能发布 1 个帖子。所以看起来我被困住了,没有更多的路要走。在硬件上花钱也是不可能的。我可能会尝试在每个消息处理中引入并行性。无论如何,谢谢,只是想确保我已经涵盖了所有内容。
    【解决方案2】:

    消息传递调整之外的一些建议,因为这似乎不是您的 [主要] 瓶颈:

    • 您提到您将数据存储到高度规范化的数据库中。这总是意味着一个或多个参考数据或 PK 查找会创建多次额外的数据库访问以获取此数据。为避免或减少这种情况,请使用所有参考数据创建本地缓存并随时更新缓存。在内存中查找将比访问数据库快得多。
    • 如果您觉得没有足够的 RAM 来缓存所有解码和参考数据,请选择基于磁盘的缓存(例如 EHCache,它将执行 RAM、磁盘或溢出)或轻量级本地数据库(如 HyperSonic 或 H2)仍然可以提供与访问 Oracle 相比,您的查找时间更短(除非您在同一台主机上,即使那样......)
    • 最终,如果每条消息都需要多次往返 DB,您可能会受益于将消息处理迁移到 DB 本身,您可以在其中使用 PL/SQL 或 Java 实现该过程。
    • 如果您为处理的一条消息写入数据库涉及多次插入/更新,请确保使用准备好的语句批处理。这将在一次调用中向数据库发送多个插入/更新。
    • 说到准备好的语句,请确保您的 JBoss DataSource configuration for Oracle 已将 prepared-statement-cache-size 设置为足够高的数字,以处理您在处理期间创建的所有准备好的语句(而不是默认为零,或者没有缓存)。
    • 您正在使用的 XML 解析器可能会增加不必要的开销,即使(或特别是)对于小消息也是如此。如果您使用的是 JAXB,请确保您没有多次(或不必要地)重新创建解组器。或者,尝试Pull/Streaming parser。如果您使用的是 DOM 解析器,则所需的额外内存可能会导致大量垃圾收集。
    • 愚蠢的事情,但值得一提的是,如果您为每条消息执行大量日志记录,那会浪费您的时间,所以请关闭它。
    • 使用 JBoss MQ 作为中间缓冲区很优雅,但它可能不是存储消息以进行延迟处理的最快方式,因为持久性更复杂,并且适用于各种 JMS 消息类型。在那一点上,如果 JBoss MQ 仍然坚持到 Oracle,那么自定义的持久性过程似乎不太可能不会更快。如果 JBoss MQ 正在存储到 HyperSonic(默认情况下),您仍然可以使用一些自定义代码来胜过 JMS 消息的存储。这也意味着您将需要一种新机制来将消息从数据库中拉出以进行处理,但与 JMS 存储一样,自定义进程的性能可能优于 JBoss MQ 实现的更通用的过程。
    • 将中间消息存储到 DB 还可以提供更大的查询灵活性,以确定不必串行处理消息的位置。 (例如,来自不同客户端的消息可能不需要按顺序处理)。当然,您也可以通过在中间消息中放置适当的标头来使用 JBoss MQ 做到这一点。这将允许您通过在多个不同的消息侦听器/处理器中使用不同的选择器来实现并行化。

    一个关于消息的快速项目.....

    您没有提到您是否在 WebSphere MQ 中使用消息驱动的 bean,但如果您使用了,Inbound Configuration 中有一个名为 pollingInterval 的设置,从文档中引用,这意味着:

    如果会话中的每个消息侦听器在其队列中没有合适的消息,则这是每个消息侦听器再次尝试从其队列中获取消息之前经过的最大间隔(以毫秒为单位)。如果会话中的任何消息侦听器经常没有合适的消息可用,请考虑增加此属性的值。仅当 TRANSPORT 的值为 BIND 或 CLIENT 时,此属性才相关。

    默认 pollingTime 为 5000 毫秒。您当前的消息处理时间是

    (3.5 * 60 * 1000 / 2000)

    = 每条消息 105 毫秒。

    如果您在这里和那里引入 5000 毫秒的暂停,这将严重降低您的吞吐量,因此您可能需要通过测量消息排队时间与您收到消息的时间之间的持续差异来研究这一点JBoss 消息侦听器中的消息。入队时间可以从这些消息头中确定:

    • JMS_IBM_PutDate
    • JMS_IBM_PutTime

    总而言之,最好的办法是弄清楚如何并行化。

    祝你好运。

    //尼古拉斯

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-14
      • 2011-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多