你真的需要消息队列吗

我是一个极简主义者,我不喜欢让软件过早或不必要地复杂化。向软件系统添加组件是增加复杂性的一种方法。让我们以消息团队为例。

消息队列是一个系统,使您能够获得容错、分布式、解耦的架构功能。在纸上,它看起来不错。

在您的应用程序中,可能有许多场景正在排队。您可以查看这篇文章,了解消息队列的优点,以了解适当的场景是什么。但不要仅仅因为它太好而不能解耦。让我们看一个示例——您希望将邮件发送出去,命令处理将被解耦。

因此,您将消息发送到消息队列,然后邮件处理系统取出消息并发送消息。如何在独立的单一类路径中实现此功能?使您的订单处理服务依赖于一个邮件服务,然后调用sendEmail()方法而不是sendToMQ()方法。如果使用消息队列,则需要定义两个系统都能识别的消息格式;如果不使用消息队列,则必须定义一个方法签名。有什么本质的区别吗?不是真的。

但你可能会有其他想要特别关注某一信息的消费者?这是有可能的,不仅仅是我们在这里谈论的项目。尽管这是可能的,但与添加另一个方法调用相比,它可能不值得。耦合吗?是的。但是这种耦合没有什么不方便的。

那么如何处理峰值流呢?您可以通过消息队列将请求放置到持久队列中,然后将它们一起处理。这是一个非常有用的特性,但它也仅限于几个因素——您的请求是在UI背景中处理的,还是需要立即响应?Serlvet容器线程池,在某种程度上可以作为队列,用户最终会得到响应,但需要等待(如果超时时间的线程太短,请求可能会丢失)。

您可以使用一个内存队列来存储较重的请求(在UI背景中处理)。注意,默认情况下,队列不是高可用性的。例如,如果消息队列节点被挂起,您的消息将丢失。因此,与其在应用程序节点中使用内存队列,还可以使用消息队列,这可能没有任何优势。

消息队列使我们能够进行异步处理——这是一个有用的特性。当用户在等待的时候,你不想做一些繁重的事情。但是您也可以使用一个内存队列或者仅仅启动一个新线程。所以还有一个问题,如果信息丢失了,会有问题吗?如果应用程序处理请求的节点,可以恢复它吗?您会发现这种情况经常发生,如果您没有处理所有的消息,那么很难确保功能是正确的。因此,只需要异步地处理沉重的调用。

将消息放到队列中另一个组件处理,对于这个场景,如果消息丢失是不可接受的,那么还有一个简单的解决方案——数据库。您可以将处理的数据存储到数据库中。然后运行调度作业,选择所有未处理的记录并异步处理它们。处理完成后,将标志设置为true。我经常使用这种方法,包括在一些大型在线系统中,它也很好用。

您还可以持续地扩展应用程序节点,只要它们在内存中没有持久的状态。无论您是否使用消息队列(临时内存处理队列都不是持久的)。

为什么我应该提供替代频繁使用的消息队列?因为如果出于不适当的原因选择它,消息队列就会成为一个负担。他们不像他们那样容易使用。首先,它有一个学习曲线。一般来说,集成的组件越多,就越容易出现问题。其次,设置和配置它的成本。例如,当消息队列需要在集群中运行时,例如多个数据中心,这就变得复杂了。

高可用性并不总是可用的——默认情况下,它不会打开。您的应用程序节点如何连接到消息队列?通过一个刷新连接池,或者使用一个短生命周期DNS记录,或者通过负载均衡器?队列可以有很多配置项和大小是多少,什么行为是(消费者需要不需要确认接受,要注重处理失败,多个消费者得到相同的消息,消息有TTL,等等)以及网络和消息传递开销,特别是现在每个人都喜欢与XML或JSON传递信息。如果过度使用消息队列,它将增加系统延迟。

最后但并非最不重要的是,如果出现问题,使用消息队列使问题跟踪非常困难。您不能在IDE中看到调用层次结构,因为一旦您将消息发送到队列,您就必须找到它正在处理的位置。这并不像听起来那么简单。你看,它增加了很多复杂性和很多值得注意的东西。

通常,消息队列在某些上下文中非常有用。当他们做的时候,我在项目中使用它们——例如,我们不想失去信息,但我们想要快速地做。我还看到它在一些不太常见的场景中使用,比如只使用一个应用程序节点,而不考虑交付哪个节点。您还可以查看stackoverflow上的问题。一些使用场景是,也许您确实需要更多的语言通信,或者您的数据流太复杂了,不要使用新的消息使用者,但是添加新的方法调用会花费很多。

如果您不确定是否没有其他更容易管理和维护的方法,请确保使用消息队列,最好不要使用。不要仅仅因为它有用就使用它——如果你真的想使用它。因为这是可能的,就像这个项目一样,消息队列不是真正必要的。

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20171209A0ETJU00?refer=cp_1026

扫码关注云+社区