5

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

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

4

2 回答 2

4

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

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

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

您没有提及是否将消息驱动的 bean 与 WebSphere MQ 一起使用,但如果您使用了,则入站配置中有一个名为pollingInterval的设置,引用文档中的内容,这意味着:

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

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

(3.5 * 60 * 1000 / 2000)

= 每条消息 105 毫秒。

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

于 2011-06-06T18:07:29.360 回答
1

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

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

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

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

于 2011-06-03T14:35:04.473 回答