【问题标题】:Concurrent IO Processing JAVA EE: Best Method?并发 IO 处理 JAVA EE:最佳方法?
【发布时间】:2012-11-09 08:10:28
【问题描述】:

我有一个 JavaEE 6 / EJB3.1 / Glassfish 3.1.2 应用程序,它从远程计算机检索 .xml 页面,将它们转换为 java 对象,然后将它们中的每一个都保存在我的 mysql 数据库中。有成千上万个这样的 .xml 页面,我只是在逐步添加它们。
这很好用,除了它非常慢(70ms 页面检索 + 转换和持久化实体的少量时间)。

我想同时进行这项工作以加快速度 - 最好的方法是什么?

可能值得注意的是:每次页面检索都会更新 mysql 数据库中用于获取页面的 OAuth 凭据的计数,如果达到最大值,则不会继续(引发异常)。我不确定这是否/多少会使事情复杂化 - 但如果两个线程看到它低于最大值,那么在更新计数之前获取页面它可能会超过最大值。

到目前为止,我的研究已将其范围缩小到两种可能性(不过,请随意添加其他可能性):

  1. Message Driven Beans - 我想,虽然可能是错误的,但我会让一个会话 bean 发送 url 消息,直到消息队列已满(比如添加了 10 个 url),然后阻塞直到队列没有满的。 Glassfish 将创建我创建的消息 bean 的 10 个实例,每个实例从其中一个 url 获取一个 .xml,更新 OAuth 计数,然后将此 .xml 作为消息发送到另一个队列,其中另一个消息 bean 可以转换并持续存在。此队列中的 xml。
  2. 使用@Asynchronous 方法并创建我自己的线程安全队列?这可能更简单,更适合我正在做的事情,但我不确定我将如何实现它。

任何建议将不胜感激!

【问题讨论】:

    标签: jakarta-ee concurrency glassfish ejb jms


    【解决方案1】:

    由于您正在处理远程服务器,您知道它的扩展性如何吗?如果你用 10 个线程来处理它,你的响应时间会变成 700 毫秒还是会保持在 70 毫秒?

    假设远程服务器可以扩展,我认为您对 MDB 的想法很满意。但是,您对此的一些想法是不准确的。您将创建提交到队列的会话 bean。我们的不同之处在于,我认为您希望在工作可用时尽快加载队列。您可以设置队列大小并告诉它是否希望在满足该大小时丢弃最旧的或最新的。我怀疑您想使用所有消息,您也可以这样做。我运行包含 100 条数千条消息的队列。您实际上只限于队列的内存大小,您可以通过使消息尽可能紧凑来进行管理。

    在消费方面,您可以将 MDB 池限制为 10 个 bean 或其他什么,这仅取决于远程服务器能够扩展到什么以及您的服务器也能够扩展什么。而不是使用 2 个队列(这只是基于您描述的问题),我只使用一个。创建一个 MDB,它可以完成您现在正在做的所有事情,即抓取 xml 并将其持久化。最后,如果您发现需要扩展,只需创建集群并添加节点即可。然后,每个节点都会有一个正在使用的 MDB 池。

    关于异步,如何控制池大小以及 MDB 提供的所有其他功能?我并不是说你不能,但似乎你是在重新发明轮子。

    【讨论】:

    • 感谢您的回答。远程服务器将能够在我可以扩展的范围内完美扩展。我只用一个保存 url 的队列和一个执行所有逻辑的 MessageDrivenBean 来实现这一点。但是,我得到:java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction 在我的 MessageDrivenBean 中的 em.merge(entity) 线上。这每 50 秒发生一次(inno_db_lock_wait_timeout)。我可以同时合并吗?还是需要分开?
    • 50s 合并?这正常吗?
    • 不,只需要几分之一秒,我想某处出现了死锁。目前我已经通过使用 bean 管理的事务解决了这个问题。我已经意识到并发问题相对复杂,而且我对事务的理解不是很好,所以我将多阅读/修改,然后看看我是否能解决它。谢谢。
    • 我已经开始整理了。如果您能确认这是实现我想要的有效方法,那将给我一些保证。我使用了一个带有:@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) @Lock(LockType.WRITE) 的 Singleton Bean 通过(单一方法)执行所有合并操作。此外,为了绕过消息生产者的 1000 条消息限制,我每添加 1000 条消息就使用 UserTransaction.begin()ut.commit()。这一切(似乎)运作良好。
    • 一旦您进入集群,您的单例将无法扩展。您是否尝试过在 MDB 上要求新事务。如果没有您的代码,很难看到您在做什么,但听起来确实不正常。
    【解决方案2】:

    完全同意普雷斯顿的观点。此外,如果您意识到需要通过添加更多节点来进行扩展,请确保配置 JMS 队列以使其接受多个消费者。这是“应用程序级”负载均衡器的典型设置,其中工作被分派给工作人员。

    【讨论】:

      猜你喜欢
      • 2015-06-29
      • 1970-01-01
      • 2010-12-19
      • 1970-01-01
      • 1970-01-01
      • 2013-03-27
      • 2021-03-27
      • 1970-01-01
      • 2016-03-02
      相关资源
      最近更新 更多