【问题标题】:Combining java spring/thread and database access for time-critical web applications为时间关键的 Web 应用程序结合 java spring/thread 和数据库访问
【发布时间】:2013-03-15 14:40:38
【问题描述】:

我正在开发一个 MVC spring web 应用程序,我想将我的用户的操作(他们点击的内容等)存储在数据库中以供离线分析。假设一个动作是一个元组(长 userId、长 actionId、日期时间戳)。我对用户的行为并不特别感兴趣,但我以此为例。

我希望很多(不同的)用户按分钟(秒)执行很多操作。因此,处理时间至关重要。

在我当前的实现中,我定义了一个带有连接池的数据源,用于将操作存储在数据库中。我从控制器的请求方法中调用了一个服务,该服务调用了一个 DAO,它将操作保存到数据库中。

这种实现效率不高,因为它等待来自控制器的调用完成并一直到数据库,然后将响应返回给用户。因此,我正在考虑将这种“动作保存”包装到一个线程中,以便对用户的响应更快。线程无需完成即可获得响应。

我对这些大规模、并发和时间关键的应用程序没有经验。因此,任何反馈/cmets 都会非常有帮助。

现在我的问题是:

  • 您将如何设计这样的系统? 你会实现一个服务,然后将它包装到一个线程中,每次操作都会调用它吗?

  • 我应该使用什么? 我检查了 spring Batch 和这个 JobLauncher,但我不确定它是否适合我。

  • 在控制器、服务、DAO 和数据源级别存在并发访问时会发生什么?

更笼统地说,设计此类应用程序的最佳做法是什么?

感谢您的帮助!

【问题讨论】:

  • 检查一下,i-develop.be/blog/2010/10/01/…,它异步发送电子邮件,所以你创建任务执行器和服务,并添加所有操作历史
  • 记录用户操作以供分析对于当前事务来说并不重要,因此异步存储它是有意义的。触发并忘记进入 jms 队列会有所帮助。

标签: java multithreading spring


【解决方案1】:

在应用程序级别获取一个单例对象,并根据每个用户操作对其进行更新。 这个单例对象应该有一个通用的 Hashmap,它应该在达到 10000 个计数的阈值级别后定期刷新,并将其作为春季批处理保存到 DB。

此外,每次处理时,定期刷新/清理到最后的记录数。我们还可以每周/每月重新初始化单例实例。请记住,如果您的应用程序部署到多个 JVM 中,这可能会导致更新相同的问题。因此,您需要在单例中实现不支持克隆的异常。

【讨论】:

  • 其实,这就是我目前正在做的事情,而且效果很好。谢谢!
【解决方案2】:

这就是我为此所做的:

使用 aspectJ 标记我要收集的用户的所有操作。 然后我使用异步 dbAppender 将其发送到 log4j...

这让您可以使用 log4j 日志记录级别打开或关闭它。

完美运行。

【讨论】:

    【解决方案3】:

    如果您对用户执行的操作感兴趣,您应该能够从他们发送的 HTTP 请求中弄清楚这一点,因此您最好将传入的请求记录在转发到您的应用程序服务器的 Apache 网络服务器中。将一组 Web 服务器放在应用程序服务器之前是一种典型的做法(它们很适合提供静态内容),而且它们通常都会记录请求。这样,日志记录将很快,您的应用程序将不必处理它,最大的工作将是编写一个脚本将日志记录到数据库中,您可以在其中进行分析。

    【讨论】:

    • 嗨,我对用户的行为并不特别感兴趣。我以此为例。我知道我可以解析网络服务器日志......但这不是我正在考虑的方法。
    • 您的问题说“我想存储我的用户的操作”,但知道您说“我对用户的操作没有特别的兴趣”您应该在问题中澄清这一点 - 人们只能给出适用于所提问题的答案...
    【解决方案4】:

    通常,在 Java EE 应用程序中生成自己的线程被认为是一种不好的形式。

    更好的方法是通过 JMS 写入本地队列,然后有一个单独的组件,例如,一个消息驱动的 bean(使用 EJB 或 Spring 很容易)将其持久化到数据库中。

    另一种方法是只写入日志文件,然后让进程读取日志文件并每天或随时写入数据库。

    要考虑的事情是:-

    • 您需要将信息保持多久?
    • 信息有多重要,你能不能丢掉一些?
    • 订单需要有多可靠?

    所有这些都将影响您处理队列/日志文件的线程数、是否需要持久 JMS 队列以及是否应该在远程系统上对主容器进行处理。

    希望这能回答您的问题。

    【讨论】:

    • 谢谢。你的解决方案很有趣。我想知道这有什么开销?据我了解,您将需要处理的对象放入队列中,并在资源可用时让另一个组件处理它们...回答您的问题,a)我不需要这些数据是最新的.可以在内存中存储一​​段时间,不时将对象转储到数据库中。 b) 数据很关键。失去任何东西都是不可接受的。 c) 顺序无关紧要,因为请求中有时间戳。谢谢!
    • 开销取决于您使用的系统、消息的数量等,但不会比使用线程更多,而且肯定是更好的方法。开销实际上来自您不能丢失任何消息的事实,您将不得不使用持久队列,这将需要根据您的容器/选项写入文件或数据库!顺便说一句,我也喜欢下面的 PATB 选项,您可以使用几个附加程序,包括 JMS、SNMP 甚至 UDP,这取决于您想要做什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 1970-01-01
    • 2011-10-22
    • 1970-01-01
    相关资源
    最近更新 更多