队列和消息队列
我是一个极简主义者, 我不想过早和不必要地使软件复杂化 。 向软件系统添加组件是增加大量复杂性的事情之一。 因此,让我们谈谈消息队列。
消息队列是使您具有容错,分布式,解耦等架构的系统。 在纸上听起来不错。
消息队列可能适合您的应用程序中的多个用例。 您可以查看这篇不错的文章 ,了解一些用例可能对MQ的好处。 但是不要急于选择MQ,因为例如,“去耦很好”。 让我们使用一个示例–您希望将电子邮件发送与订单处理分离。
因此,您将一条消息发布到一条消息队列中,然后电子邮件处理系统将其提取并发送电子邮件。 您如何在整体式,单一类路径应用程序中执行此操作? 只需使您的订单处理服务依赖于电子邮件服务,然后调用sendEmail(..)
而不是sendToMQ(emailMessage)
。 如果使用MQ,则定义两种系统都可以识别的消息格式。 如果不使用MQ,则定义方法签名。 实际区别是什么? 不多,如果有的话。
但是,那么您可能希望能够添加另一个对给定消息执行其他操作的使用者? 确实可能发生这种情况,但这不是针对常规项目的。 即使只是这样,与仅添加另一个方法调用相比,这也不值得。 耦合–是的。 但不是不方便耦合。
如果要处理峰值怎么办? 消息队列使您能够将请求放入持久队列并处理所有请求。 这是一项非常有用的功能,但又受到几个因素的限制-您的请求是在UI后台处理还是需要立即响应? Servlet容器线程池可用作排序队列–最终将提供响应,但用户将不得不等待(如果线程获取超时太小,则请求将被丢弃)。 或者,您可以将内存队列用于较重的请求(在UI后台处理)。 请注意,默认情况下,您的MQ可能不是高度可用。 例如,如果MQ节点死亡,则会丢失消息。 因此,与应用程序节点中的内存队列相比,这没有什么好处。
这导致我们进行异步处理–这确实是一个有用的功能。 用户不想在等待时进行大量计算。 但是您可以使用内存中的队列,也可以只是启动一个新线程(a-la spring的@Async注释)。 这是另一个方面–丢失消息是否重要? 如果您处理请求的应用程序节点死亡,可以恢复吗? 您会惊讶于它实际上无关紧要的频率,并且您可以在不保证所有消息都得到处理的情况下正常运行。 因此,仅异步处理较重的调用可能会很好。
即使您承受不起丢失消息的麻烦,将消息放入队列中以便另一个组件处理消息的用例,仍然有一个简单的解决方案–数据库。 您在数据库中放置了一个带有处理=假标志的行。 计划的作业运行,选择所有未处理的作业并异步处理它们。 然后,当处理完成时,将标志设置为true。 我已经多次使用这种方法,包括大型生产系统,而且效果很好。
只要您的应用程序节点中没有任何持久状态,您仍然可以无限扩展它们 。 不管您是否正在使用MQ。 (临时的内存中处理队列不是持久状态)。
为什么我要尝试替代消息队列的常用用法? 因为如果选择错误的原因,MQ可能会成为负担。 它们听起来并不容易使用。 首先,有一个学习曲线。 通常,集成的组件越多,可能出现的问题就越多。 然后是设置和配置。 例如,当MQ必须在集群中的多个数据中心(对于HA)中运行时,这变得很复杂。 高可用性本身并非无关紧要-通常默认情况下不会将其打开。 您的应用程序节点如何连接到MQ? 通过刷新的连接池,使用短暂的DNS记录,通过负载平衡器? 然后,您的队列将进行大量的配置-它们的大小,行为是什么(使用者应该明确确认接收,是否应该明确确认对消息的处理失败,是否应该由多个使用者获得同一条消息,消息应该具有TTL等)。 然后是网络和消息传输的开销–特别是考虑到人们经常选择JSON或XML来传输消息 。 如果您过度使用MQ,那么它将增加系统延迟。 最后,但并非最不重要的一点是,在分析问题时更难跟踪程序流程。 您不能仅在IDE中看到“调用层次结构”,因为一旦将消息发送到MQ,就需要去查找处理该消息的位置。 这并不总是听起来那么琐碎。 您会看到,它增加了很多复杂性和需要注意的事情。
当然,MQ在某些情况下非常有用。 我一直在真正适合他们的项目中使用它们-例如,我们承受不起丢失消息的麻烦,我们需要快速处理(因此无法对数据库执行ping操作)。 我也看到过它在非平凡的场景中使用,在该场景中,我们习惯于在单个应用程序节点上使用消息,而不管哪个节点发布消息(发布/订阅)。 您还可以检查这个stackoverflow问题 。 也许您确实需要使用多种语言进行交流(但不希望使用ESB),或者您的流程变得如此复杂,以至于添加一个新的方法调用而不是一个新的消息使用者就太过分了。
因此,我在这里要说的只是陈腔滥调:“您应该为工作使用正确的工具”。 如果您尚未确定消息队列的真正用途,而该消息队列不能以不同,更易于设置和维护的方式轻松处理,则不要选择消息队列。 而且不要以“以防万一”开头的MQ开头-每当您意识到实际需要时就添加它。 因为可能在外面的常规项目中不需要消息队列。
翻译自: https://www.javacodegeeks.com/2014/07/you-probably-dont-need-a-message-queue.html
队列和消息队列