MQ 的优势

1.通过持久性冗余

冗余是消息队列最明显的优势之一。应用程序崩溃,超时,代码中的错误以及其他问题只是常态的一部分。在每月处理数百万或数十亿交易的应用程序中尤其如此。

队列通过使读取消息的进程确认它已完成事务并且可以安全地删除它来帮助实现冗余。如果出现任何问题,最糟糕的情况是,该消息会持久保存到某处,并且不会丢失。它可以在以后重新处理。

2.交通高峰期

您并不总是确切知道您的应用程序将拥有多少流量。例如,在Stackify,我们每个月会收到数十亿条消息。我们无法知道客户将要发送给我们的是什么。通过对数据进行排队,我们可以确保数据将被保留,然后最终被处理,即使这意味着由于高流量峰值,它需要比平常更长的时间。

3.改进Web应用程序页面加载时间

队列在Web应用程序中非常有用,可以在后台线程中执行复杂的逻辑,因此请求可以快速完成。如果有人在您的网站上下订单,那可能涉及许多不同的事情。您可以为用户执行最小化并返回成功,并在后台线程中启动其余部分以完成,而无需使用完整的消息排队系统和后台应用程序。大多数编程语言现在都有办法做到这一点。示例:Resque,Hangfire等

4.追求效率

批处理是使用消息队列的一个很好的理由。将100条记录一次插入数据库而不是一次插入100条记录要高效100次。我们在elasticsearch和SQL Server中插入了大量数据。批处理有助于我们通过调整事务的大小来优化其性能。

5.异步消息

在应用程序需要完成某些任务但现在不需要完成但甚至不关心结果的情况下,队列可能很棒。您可以将消息写入队列,然后让相同的业务逻辑发生,而不是调用Web服务并等待它完成。队列是实现异步编程模式的绝佳方法。

6.使用数据合同解耦

通过在软件的不同部分之间使用队列,您可以解除硬依赖关系。队列中的消息格式成为您的数据协定,任何知道如何读取该消息格式的内容都可用于处理事务。这对于甚至用不同编程语言编写的代码部分也很有用。

7.交易排序和并发挑战

如果有1000个人一次在您的网站上下订单,那么可能会产生一些并发问题,并确保首先完成第一个订单。

通过对它们进行排队,您可以保证它们的顺序并控制甚至同时处理的数量。

8.提高可扩​​展性

消息队列使您可以解耦应用程序的不同部分,然后单独扩展它们。

使用Azure,AWS或其他托管解决方案,您甚至可以根据CPU使用率或其他指标动态扩展该后台服务。消息队列可以提供可扩展性和弹性方面的帮助。

9.创造弹性

通过打破您的应用程序并按队列分隔不同的组件,您固有地创建了更多的弹性。即使订单的后端处理的一部分稍有延迟,您的网站仍然可以运行。在Stackify,我们设计传入的API,尽可能少地排队数据,以确保没有其他任何东西可以降低接收数据的能力。即使SQL Server关闭,我们也希望能够接受数据!

10.保证交易发生一次

消息队列设计为事务性的。当您从队列中读取消息时,必须告诉它在完全从队列中删除之前完成处理消息的位置。这有助于确保事务只发生一次。  

11.将更大的任务分解为许多较小的任务

队列的另一个好用途是将更大的任务分解成许多小块然后将它们排队。我们在Stackify有一个很好的例子。如果编辑一组服务器的监视模板,则需要更新使用该模板的每台服务器上的监视器。我们可以为每个服务器排队一条消息,并可能将它们作为较小的操作同时进行。  

12.监测

消息队列系统使您可以监视队列中的项目数,处理消息的速率以及其他统计信息。从应用程序监视的角度来看,这非常有用,可以关注数据如何在系统中流动以及是否需要备份。

现在公司就是利用 Kafka 手机日志信息,将一些信息写入 ES, Kibana 等也是使用的这种方式。

MQ 的缺点

  1. 引入消息中间件,增加复杂性。

  2. 消息没有反馈,无法得知消费者的使用情况。

如果只是为了异步处理,完全没必要引入 MQ。

你或许没有必要引入 MQ

我是一个极简主义者,我不喜欢过早和不必要地使软件复杂化。将组件添加到软件系统是增加大量复杂性的事情之一。那么让我们来谈谈消息队列。

消息队列是允许您具有容错,分布式,解耦等架构的系统。这听起来不错。

消息队列可能适合您应用程序中的多个用例。您可以查看这篇关于MQ的优点的好文章,了解一些用例可能是什么。但是,不要急于选择MQ,因为“脱钩是好的”,

例如。让我们使用一个示例 - 您希望您的电子邮件发送与订单处理分离。因此,您将邮件发布到邮件队列,然后电子邮件处理系统将其选中并发送电子邮件。您将如何在单一的单类路径应用程序中执行此操作?只需使您的订单处理服务依赖于电子邮件服务,并调用sendEmail(..)而不是sendToMQ(emailMessage)。如果使用MQ,则定义要由两个系统识别的消息格式;如果您不使用MQ,则定义方法签名。有什么实际区别?没有多少,如果有的话。

但是,您可能希望能够添加另一个使用给定消息执行其他操作的消费者?而这可能确实发生,它不适合那里的常规项目。即使是这样,与仅添加另一个方法调用相比,它也不值得。耦合 - 是的。但不是不方便耦合。

如果你想处理尖峰怎么办?消息队列使您能够将请求放入持久队列并处理所有这些请求。这是一个非常有用的功能,但它又基于几个因素而受到限制 - 您的请求是在UI背景中处理还是需要立即响应? servlet容器线程池可用作排序队列 - 最终将提供响应,但用户必须等待(如果线程获取超时太小,请求将被丢弃)。或者,您可以使用内存中队列来处理较重的请求(在UI背景中处理)。请注意,默认情况下,您的MQ可能不具备高可用性。例如。如果MQ节点死亡,则会丢失消息。因此,这不是应用程序节点中内存中队列的优势。

这导致我们进行异步处理 - 这确实是一个有用的功能。在用户等待时,您不希望进行繁重的计算。但是你可以使用内存中队列,或者只是启动一个新线程(a-la spring的@Async注释)。

这是另一个方面 - 消息丢失是否重要?如果你的应用程序节点,处理请求,死了,你能恢复吗?您会惊讶地发现它实际上并不重要,并且您可以在不保证所有消息都得到处理的情况下正常运行。因此,只是异步处理较重的调用可能会很好。

即使你不能丢失消息,将消息放入队列以便其他组件处理它的用例,仍然有一个简单的解决方案 - 数据库。您在数据库中放入了一个带有processed = false标志的行。计划的作业运行,选择所有未处理的作业并异步处理它们。然后,处理完成后,将标志设置为true。我已经多次使用过这种方法,包括大型生产系统,而且效果很好。

只要您没有任何持久状态,您仍然可以无限扩展应用程序节点。无论您是否使用MQ。 (临时内存中处理队列不是持久状态)。

为什么我要尝试替代消息队列的常见用法?因为如果选择错误的原因,MQ可能是一种负担。它们不像听起来那么容易使用。首先,有一个学习曲线。通常,您拥有的独立集成组件越多,可能出现的问题就越多。然后是设置和配置。例如。当MQ必须在集群中运行时,在多个数据中心(对于HA)中,这变得复杂。高可用性本身并非易事 - 默认情况下它通常不会打开。您的应用程序节点如何连接到MQ?通过刷新连接池,使用短期DNS记录,通过负载均衡器?然后你的队列有大量的配置 - 它们的大小,它们的行为是什么(如果消费者明确承认收到,如果他们明确承认未能处理消息,是否有多个消费者得到相同的消息,消息是否有TTL等)。然后是网络和消息传输开销 - 特别是考虑到人们经常选择JSON或XML来传输消息。如果过度使用MQ,则会增加系统的延迟。最后,但并非最不重要的是 - 在分析问题时更难跟踪程序流程。您不能只在IDE中看到“调用层次结构”,因为一旦向MQ发送消息,您需要去查找它的位置。

个人感受

MQ 做的部分事情,完全可以多线程+数据库去完成。

当然,这是针对单系统。如果是如今的分布式系统,其实 RPC 就可以完成很多事情。目前的 Dubbo2.0 已经支持异步。

拓展阅读

协议标准

JMS-java 消息服务标准

AMQP-高级消息队列协议

Kafaka

Apache-Kafaka 入门

Apache-Kafaka 为什么这么快

Spring Kafka 整合

Docker Kafka

ActiveMQ

ActiveMQ 入门

ActiveMQ 通讯模式

Docker ActiveMQ

ActiveMQ Transaction

Spring ActiveMQ 整合

RabbitMQ

RabbitMQ 系列

RabbitMQ Docker

Spring AMQP

RocketsMQ

RocketsMQ-alibaba 开源项目

手写

手写 MQ

个人心得

  1. 相关的实现特别多。只需要掌握其中的思想+熟练使用其中的一个即可。

  2. 至于代码的实现。需要在掌握 Netty+RPC+LevelDB 之后,才进行实现。

参考资料

  • 搜索关键词

message queue use cases

缺点

YOU PROBABLY DON’T NEED A MESSAGE QUEUE

优点

Top 10 Uses For A Message Queue

real-world-use-of-jms-message-queues

Message Queues & You – 12 Reasons to Use Message Queuing