如何提高基于 MQ 的批处理应用程序的性能?

发布于 2024-11-11 15:13:35 字数 615 浏览 9 评论 0原文

我有一个应用程序,消息以每小时 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消息的顺序非常重要,因此我们无法进行并行处理。

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

I have an application where messages keep coming at a rate of 70K XMLs per hour. We consume these XML messages and store it into an intermediate queue. The intermediate queue is created because we need to meet SLA of consuming all the messages with 24 hours. We are able to consume and load the XMLS into the internal queue within 24 hours. After loading it to internal queue, we process the XMLS (parse, apply very few transformation, perform very few validations) and store the data to a heavily normalized data model. I know that the datamodel can have a huge impact on performance, unfortunately, we have no control over the datamodel. Currently, we take 3.5 minutes to process 2K messages, which is unacceptable. We want to bring it down to 1 minute for 2K messages. Here is what we have done so far:

1) Applied indexes wherever applicable.
2) Use XMLBeans for parsing the XMLs (size of each XML is not very huge)
3) Removed all unnecessary validations, transformatios, etc.

The application runs on:
Operating system: RHEL 5.4 64 bit
Platform: JDK 1.6.0_17, 64 bit
Database: Oracle 11g R2 64 bit (2 node cluster)
External MQ: IBM Queue
Internal temporary storage MQ: JBoss MQ
Application Server: Jboss 5.1.0.GA (EAP Version)

The order in which we consume and process the XML messages is very important and so we cannot do a parallel processing.

Is there anything else we can do to improve performance?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦中楼上月下 2024-11-18 15:13:35

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

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

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

您没有提到您是否在 WebSphere MQ 中使用消息驱动 bean,但如果您是,则 入站配置 称为pollingInterval引用文档,这意味着:

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

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

(3.5 * 60 * 1000 / 2000)

= 每条消息 105 毫秒。

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

  • JMS_IBM_PutDate
  • JMS_IBM_PutTime

总而言之,您最好的选择是弄清楚如何并行化。

祝你好运。

//尼古拉斯

Some suggestions outside of message delivery tuning since it appears this is not your [primary] bottleneck:

  • You mentioned you are storing data into a highly normalized database. This invariably means one or more reference data or PK lookups which creates several additional trips to the database to fetch this data. To avoid or reduce this, create a local cache with all your reference data and update the cache as you go. In memory lookups will be significantly faster than a trip to the DB.
  • If you feel you have insufficient RAM to cache all your decodes and reference data, shoot for a disk based cache (e.g. EHCache which will do RAM, Disk or Overflow) or a lightweight local DB like HyperSonic or H2 which will still give you better lookup times than a trip to Oracle (unless you're on the same host, and even then....)
  • Ultimately, if each message requires many round trips to the DB, you may benefit from migrating the processing of the message to the DB itself, where you can implement the process in PL/SQL or Java.
  • If your write to the database for one message processed involves multiple inserts/updates, make sure to use prepared statement batching. This will send multiple inserts/updates in one call to the DB.
  • Speaking of prepared statements, make sure your JBoss DataSource configuration for Oracle has prepared-statement-cache-size set to some number high enough to handle all your prepared statements created during processing (and not the default which is zero, or no caching).
  • The XML parser you are using may be imposing more overhead than is necessary, even (or especially) for small messages. If you are using JAXB, make sure you're not recreating the unmarshaller more than once (or more than necessary). Alternatively, try a Pull/Streaming parser. If you are using a DOM parser, the additional memory required may be causing a lot of garbage collection.
  • Silly thing, but worth mentioning, if you are executing a lot of logging for each message, that will be costing you time, so turn it off.
  • Using JBoss MQ as an intermediary buffer is elegant but it is probably not the fastest way to store your messages for deferred processing since the persistence is more complex and generalized for all sorts of JMS message types. On that note, if JBoss MQ is persisting to Oracle anyways, then it seems improbable that a custom persistence procedure would not be faster. If JBoss MQ is storing to HyperSonic (as it does by default), you can still probably outperform the store of the JMS message with some custom code. This will also mean that you will need a new mechanism to pull the message back out of the DB for processing, but as with the JMS store, a custom process may outperform the more generalized procedure implemented by JBoss MQ.
  • Storing intermediary messages to the DB may also give more query flexibility to determine where messages do not have to be serially processed. (Perhaps, for example, messages originating from different clients do not need to be processed in sequence). Of course, you can also do this with JBoss MQ by placing the appropriate headers in the intermediary messages. This would allow you to parallelize by using different selectors in multiple different message listeners/processors.

One quick item on messaging.....

You did not mention if you were using message driven beans with WebSphere MQ, but if you are, there is a setting in the Inbound Configuration called pollingInterval which, to quote from the docs, means:

If each message listener within a session has no suitable message on its queue, this is the maximum interval, in milliseconds, that elapses before each message listener tries again to get a message from its queue. If it frequently happens that no suitable message is available for any of the message listeners in a session, consider increasing the value of this property. This property is relevant only if TRANSPORT has the value BIND or CLIENT.

The default pollingTime is 5000 ms. Your current message processing time is

(3.5 * 60 * 1000 / 2000)

= 105 ms per message.

If you introduce a 5000 ms pause here-and-there, that will seriously cut down on your throughput, so you might want to look into this by measuring the ongoing difference between the message enqueue time and the time that you receive the message in your JBoss message listener. The enqueue time can be determined from these message headers:

  • JMS_IBM_PutDate
  • JMS_IBM_PutTime

All in all, your best bet is going to be to figure out how to parallelize.

Good luck.

//Nicholas

神也荒唐 2024-11-18 15:13:35

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

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

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

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

WebSphere MQ, even on a small server, can unload messages MUCH faster than the rate you describe. The Windows Performance Report for WMQ V7 tested at more than 2,200 2k persistent round trips (one request and one reply) per second over client channels. That's more than 4,000 messages per second.

The bottleneck in your case would seem to be the latency of processing messages and the dependency on processing the messages in a particular order. The option that could give you the MOST performance boost would be to eliminate the order dependency. When I worked at a bank we had a system that posted transactions in the exact order they arrived and everyone said this requirement was mandatory. However, we eventually revised the system to perform a memo-post during the day and then repost in a later step. The memo-posting occurred in any order and supported parallelism, failover and all the other benefits of multi-instance processing. The final post applied the transactions in logical order (and in fact in an order that was most favorable to the customer) once they were all in the DB. Sequence dependencies lock you into a singleton model and are a worst-case requirement for asynch messaging. Eliminate them if at all possible.

The other area for improvement will be in the parsing and processing of the messages. As long as you are stuck with sequence dependencies, this is the best bet for improving performance.

Finally, you always have the option to throw money at the problem in the form of more memory, CPU, faster disk I/O and so forth. Essentially this is addressing software architecture with horsepower and is never the best solution but often it buys you enough time to address the root cause.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文