顺序护航模式
按定义的顺序处理一组相关的消息,不需阻止对其他消息组的处理。
上下文和问题
应用程序通常需要按照消息到达的顺序处理一系列消息,同时仍能够横向扩展来处理增加的负载。 在分布式体系结构中,按顺序处理这些消息并不简单,因为辅助角色可以使用 竞争使用者模式独立缩放且经常独立拉取消息。 例如,订单跟踪系统接收包含订单的账本以及这些订单的相关操作。 这些操作可以是创建订单、将事务添加到订单、修改过去的事务或删除订单。 在此系统中,必须以先出 (FIFO) 方式执行操作,但只能在订单级别执行。 但是,初始队列接收一个账本,其中包含许多订单的事务,这些事务可能会交错。
解决方案
将相关消息推送到队列系统中的类别,并让队列侦听器锁定并仅从一个类别(一次一条消息)拉取。 下面是常规顺序车队模式的外观: 在队列中,可以交错不同类别的消息,如下图所示:
问题和注意事项
在决定如何实现此模式时,请考虑以下几点:
- 类别/缩放单位。 可以横向扩展传入消息的哪些属性? 在订单跟踪方案中,此属性是订单 ID。
- 吞吐量。 目标消息吞吐量是什么? 如果它非常高,可能需要重新考虑 FIFO 要求。 例如,是否可以强制实施开始/结束消息,按时间排序,然后发送批处理进行处理?
- 服务功能。 选择的消息总线是否允许一次性处理队列或队列类别中的消息?
- 可进化性。 如何将新类别的消息添加到系统? 例如,假设上面所述的账本系统特定于一个客户。 如果需要载入新客户,是否可以拥有一组按客户 ID 分配工作的账本处理器?
- 由于发送消息时网络延迟可变,使用者可能会按顺序接收消息。 请考虑使用序列号来验证排序。 还可以在事务的最后一条消息中包含特殊的“序列结束”标志。 Spark 或 Azure 流分析等流处理技术可以在时间范围内按顺序处理消息。
何时使用此模式
在以下情况下使用此模式:
- 你有消息按顺序到达,并且必须按相同的顺序进行处理。
- 到达的消息或可以“分类”的方式,使类别成为系统的缩放单位。
此模式可能不适合:
- 非常高的吞吐量方案 (数百万条消息/分钟或秒) ,因为 FIFO 要求会限制系统可以执行的缩放。
示例
在 Azure 上,可以使用Azure 服务总线消息会话来实现此模式。 对于使用者,可以将逻辑应用与服务总线速览锁连接器配合使用,也可以使用服务总线触发器Azure Functions。 对于上一个订单跟踪示例,按照收到的顺序处理每个账本消息,并将每个事务发送到另一个队列,其中类别设置为订单 ID。 在这种情况下,事务永远不会跨越多个订单,因此使用者会并行处理每个类别,但该类别中的 FIFO。 引导处理器通过取消批处理第一个队列中每个消息的内容来扇出消息: 账本处理器负责:
- 一次一次走账本一个事务。
- 设置消息的会话 ID 以匹配订单 ID。
- 将每个账本事务发送到会话 ID 设置为订单 ID 的辅助队列。
使用者侦听辅助队列,在该队列中按顺序处理具有匹配顺序 ID 的所有消息。 使用者使用 速览锁 模式。 考虑可伸缩性时,账本队列是主要瓶颈。 发布到账本的不同事务可以引用相同的订单 ID。 但是,消息可以在账本 后 扇出到无服务器环境中的订单数。
后续步骤
实现此模式时,以下信息可能相关:
- 消息会话:先进先出 (FIFO)
- 扫视-锁定消息(非破坏性读取)
- 为了在逻辑应用中使用服务总线会话 ( MSDN 博客) 传送相关消息