竞争消费模式

使多个并发的消费者来处理同一消息收发信道接收到的消息。

这种模式使系统能够同时处理多个消息以优化吞吐量,提高扩展性和可用性,并且以平衡的工作量。

背景与问题

在云中运行的应用程序可以预期处理大量的请求。而不是过程中的每个请求的同步,常用的技术是应用程序通过消息系统来处理这些异步其它服务(消费者服务)来传递他们。

这种策略有助于确保当请求正在处理中的应用程序的业务逻辑没有被阻塞。

请求的数目可能会随着时间的推移等原因变化比较显著。

在用户活动或自多个租户的请求突然爆发可能会导致不可预知的工作负荷。在高峰时间系统可能需要每秒处理数以百计的请求,而在其他时间的可能是非常小的。此外,工作性质执行以处理这些请求可能是高度可变的。利用单一消费者服务可能导致该实例充斥着请求或消息系统过载当从一个涌入而来的消息应用。为了处理这种波动的工作负荷,系统可以运行多个消费者服务实例。然而,这些消费者必须协调,以确保每个消息只传送到单一的消费者。工作负荷也需要负载跨越消费者平衡,以防止一个实例成为瓶颈。

解决方案

使用消息队列来实现应用和消费者服务实例之间的通信信道。应用程序提交标段的消息请求到消息队列,以及消费者服务实例从队列接收消息并对其进行处理。

这种方法使同一池的消费者服务实例处理任何应用程序实例的消息。

图1示出了该架构。

架构

优点

  • 负载均衡

它是一种固有的负荷调平系统,可以处理应用程序发送批量请求的变化比较大的情况。

队列在应用程序实例和客户服务的之间充当一个缓冲,它可以最大限度减少应用程序和服务实例在可用性和响应的影响。

处理一个消息需要长时间运行只到被处理完毕但不会阻止消费者服务实例的其他消息并发。

  • 可靠性

它提高了可靠性。当然生产者与消费者直接通信而取代使用这种模式,但不监视消费者,消息会可能丢失或失败的可能性比较高,如果消费者无法进行处理。

在这种模式消息不发送到一个特定的服务实例,失败的服务实例将不会阻止一个生产者,且消息可以通过任何工作服务实例进行处理。

  • 解耦

它不需要在消费者之间,或生产者和消费者的实例之间进行复杂的协调。消息队列确保每个消息被传递至少一次。

  • 可扩展性

它是可扩展的。该系统可以动态增加或减少消费者服务的实例数目满足消息的体积波动。

  • 容错性

它可以提高应变能力如果消息队列的提供事务读取操作时。

如果消费者服务实例读取和处理该消息作为事务操作的一部分,并且如果这种消费服务实例随后发生故障时,该模式可以确保消息将被返回到队列并被另一个消费者服务实例拾起和处理。

问题和注意事项

  • 消息订购(Message Ordering)

在消费者服务实例接收消息的顺序不能保证,并不一定反映在其中创建的消息的顺序。

设计系统,确保信息处理等幂的,因为这将有助于消除在消息的处理顺序上的任何依赖。

幂等性相关

  • 设计服务弹性(Designing Services for Resiliency)

如系统被设计为检测和重新启动当服务初始化失败,可能有必要实施处理并由服务实例作为幂运算执行,以尽量减少检索和处理一次以上的单个消息的影响的处理。

  • 检测有害消息(Detecting Poison Messages)

格式不正确的消息或需要访问不可用的资源的任务,可能会造成服务实例失败。

该系统应防止这样的消息被返回到队列,而是捕获和在别处存储这些消息的细节,以便它们可以在需要进行分析。

  • 处理结果(Handling Results)

服务实例处理的消息是从生成该消息的应用程序逻辑完全解耦,并且它们未必能够直接进行通信。

如果服务实例生成的结果必须传递回应用程序逻辑,此信息必须被存储在是两者可访问的位置,并且系统必须提供当处理已经完成,以防止从检索不完全数据的应用程序逻辑的一些指示。

  • 伸缩的消息系统(Scaling the Messaging System)

在一个大型可伸缩性的解决方案中,一个消息队列由消息的数量未知而不知所措,成为在系统中的瓶颈。

在这种情况下,考虑分割该消息系统以引导从特定生产者的信息到一个特定的队列,或使用负载平衡通过多个消息队列分发消息。

  • 消息系统的可靠性保障(Ensuring Reliability of the Messaging System)

需要一个可靠的消息传递系统来保证,一旦应用程序排队的消息,它也不会丢失。

这是确保所有消息都至少有一次交付至关重要。

什么时候用这个模式

应用场景

  1. 一个应用程序的工作负荷被分成可以异步运行任务。

  2. 任务是独立的,并且可以并行地运行。

  3. 工作容积是高度可变的,因此需要一种可扩展的解决方案。

  4. 该解决方案必须提供高可用性,并且如果一个任务的处理失败,必须是有弹性的。

  5. 对应用程序的工作负荷分割成离散的任务是不容易的,或者任务之间有高度的依赖。

  6. 任务必须同步进行,并且应用程序逻辑必须等待任务完成后再继续。

  7. 任务必须以特定的顺序来执行。

ps: 竞争模式能够保证执行的顺序吗?

注意

一些消息系统支持会话,使生产者对消息进行分组在一起,并确保它们都被同一个接收者处理。该机制可以与优先消息中使用(如果它们支持)来实现消息排序的形式,从生产者传送消息中的序列到单个消费者。

拓展阅读

相关模式

参考资料

  • 官方

https://docs.microsoft.com/en-us/azure/architecture/patterns/competing-consumers

https://www.enterpriseintegrationpatterns.com/patterns/messaging/CompetingConsumers.html

  • other

https://www.cnblogs.com/zsy/p/5210538.html