使用消息队列的 Web 应用程序架构

Posted

技术标签:

【中文标题】使用消息队列的 Web 应用程序架构【英文标题】:Architecture of a web application using message queues 【发布时间】:2014-04-09 11:03:11 【问题描述】:

我有一个 java web 应用程序,它使用某种形式的自定义消息队列,通过数据库表 (EmailQueue) 来排队发送电子邮件。该应用程序部署在 Tomcat 上,并使用 Quartz 作业轮询 EmailQueue 表中要发送的新条目。

我现在需要添加一些其他类型的作业和消息(通知、短信等)的队列,因此我正在考虑使用适当的消息队列(RabbitMQ、ActiveMQ 等)而不是数据库。这是由 few articles 提出的,他们认为不应将数据库用作队列。

不过,我还没有完全了解整个生态系统,希望得到一些指导。具体来说:

在 Web 应用程序的上下文中,消息队列代理是否通常像数据库一样作为自己的进程运行?我需要在服务器重新启动时保持消息的持久性。 应该将消息队列消费者部署为 Tomcat 中的 servlet 还是独立的 Java 应用程序?我对这一切的可管理性特别感兴趣(即启动/停止实例、配置、监控)相关 question 和 email thread。

【问题讨论】:

你可以有一个嵌入式队列——Spring 提供了一个简单的嵌入式代理。但正如您所指出的,这将代理与 Web 服务器的生命周期联系在一起,或者更糟糕的是,与应用程序本身联系在一起。外部代理更为常见——可能在同一台服务器上运行。就处理程序而言,您可以将它们放在任何地方;您是否希望他们在应用程序停机期间继续处理/排队消息?只需将它们作为服务器上的守护程序服务。然而beware this antipattern. 似乎将代理作为单独的进程运行确实更合适。我将阅读那篇文章并浏览 ActiceMQ in Action 以获得更多见解。与 Tomcat servlet 相比,我担心服务器上守护程序服务的监控和管理。可能有解决方案,但我不知道它们。 【参考方案1】:

1.在 Web 应用程序的上下文中,消息队列代理是否通常像数据库一样作为自己的进程运行?我需要在服务器重新启动时保持消息的持久性。

消息队列代理通常作为自己的进程运行。使用 RabbitMQ,您的生产者可以将消息定义为持久性。

2.消息队列消费者应该部署为 Tomcat 中的 servlet 还是独立的 Java 应用程序?我对这一切的可管理性特别感兴趣(即启动/停止实例、配置、监控)相关问题和电子邮件线程。

关于我在类似主题here 上的问题,我最终将我的消费者部署为 Tomcat 应用程序,这确实为我提供了我也在寻找的可管理性。这让我可以编写 servlet 来监控和管理队列。

此解决方案还适用于可扩展性,这对于消息传递和排队很重要。通过拍摄运行 Tomcat 的服务器的快照(我使用的是 Amazon EC2 实例)并将该快照部署到新实例上,我还能够轻松地动态扩展消费者数量。我已将 Tomcat 配置为作为服务自动启动,这样当新实例启动时,消费者 .war 文件将部署并自动开始使用。

但是,正如我在问题中所讨论的那样,请注意线程。我最初遇到了停止 Tomcat 的问题。

不过,您也可以使用 JMX 将消费者作为独立的 Java 应用程序实现可管理性。使用 JConsole,您可以远程访问您的 Java 应用程序并在运行时查询/更新参数。许多监控程序,例如 Zabbix,都可以使用 JMX 连接到应用程序。

如果您喜欢 Web 开发和构建自己的 Web 应用程序,我会选择 Tomcat 路线。希望对您有所帮助。

【讨论】:

另外,我使用了 RabbitMQ(出于多种原因),但 AMQP 是跨平台互操作的。我不后悔这个决定。 我认为将 Web 应用程序用作消费者是对 Tomcat 的滥用。它最初可能会使管理更容易,但它们不是 Web 应用程序,因此不应这样部署。 感谢您的意见@littleK。我希望能够在没有 Tomcat 的情况下部署消息处理实例,而且我倾向于 Boris the Spider 的论点,所以我现在正在探索独立的 java 进程。无论如何,我总是可以稍后切换到 Tomcat。无论如何,经纪人绝对是独立的。【参考方案2】:

不错的选择!面向消息的中间件已经编写好了,可以省去一些麻烦——而不是重新发明***。

    在完整的 Java EE 服务器中,消息传递系统通常是一个集成部分。 对于 tomcat,请查看 TomEE+ 或类似内容,了解 ActiveMQ 和 Tomcat 如何协同工作。

ActiveMQ 可以轻松地部署为 servlet 中的嵌入式代理或独立进程。这只是可管理性和您喜欢的问题。我会考虑一个独立的 ActiveMQ,因为您可能希望在某些情况下添加更多的 Tomcat 服务器,并将两者都指向同一个 ActiveMQ 服务器。 RabbitMQ 不是在 Java 上运行,而是在 Erlang 平台上运行 - 所以这是不同的。

    这取决于您的架构以及您觉得管理起来更舒适的方式。部署为 servlet 似乎是一种合理的方法,因为您可能已经有了监控和其他功能。

您也可以在 ActiveMQ 本身内部运行邮件服务。您可以轻松地将 spring bean 嵌入到 ActiveMQ 配置中 - 或者,最好使用 mail functionality 运行 Camel Routes,它可以通过简单的 XML 配置来完成这些事情。如果您在邮件消费者中有很多逻辑,则应该将其作为 servlet 应用程序的一部分。

【讨论】:

感谢@Petter 提供的信息。它让我走上了正确的轨道。我现在不使用 Spring,所以我不会走那条路,但很高兴知道。

以上是关于使用消息队列的 Web 应用程序架构的主要内容,如果未能解决你的问题,请参考以下文章

大型网站架构系列:消息队列

大型网站架构系列:消息队列

一文详解消息队列的常见功能场景与使用精髓

网站架构:消息队列

大型网站架构系列:消息队列(转)

大型网站架构系列:消息队列