你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

协调模式

Azure 事件网格
Azure 服务总线

分散工作流程逻辑,并将职责分配给系统内的其他组件。

上下文和问题

基于云的应用程序通常被划分为几项小型服务,这些服务以端到端的方式协同处理业务事务。 即使单个操作(在事务内)也可能会在所有服务之间进行多个点到点调用。 理想情况下,这些服务应为松散耦合。 设计分布式、高效且可缩放的工作流很有挑战性,因为这通常涉及复杂的服务间通信。

常见的通信模式是使用集中式服务或编排器。 在将操作委派给相应的服务时,传入的请求流经编排器。 每个服务只是完成了他们的职责,并不了解整个工作流程。

使用中央编排器处理请求的工作流示意图。

编排器模式通常作为自定义软件实现,并且具有关于这些服务职责的域知识。 一个好处是,编排器可以根据下游服务执行的单个操作的结果来整合事务的状态。

但是,也存在一些缺点。 添加或删除服务可能会破坏现有逻辑,因为需要重新连接通信路径的某些部分。 这种依赖关系使得编排器实现变得复杂且难以维护。 协调器可能会对工作负载的可靠性产生负面影响。 在负载下,它可能会带来性能瓶颈,并成为单一故障点。 同时还可能导致下游服务发生连锁故障。

解决方案

在服务之间委派事务处理逻辑。 让每个服务决定并参与业务操作的通信工作流。

此模式是最大程度地减少对集中通信工作流的自定义软件的依赖的方法。 组件在彼此之间不进行直接通信的情况下编排工作流,从而实现通用逻辑。

实现编排的一种常用方法是使用消息中转站来缓冲请求,直到下游组件声明并处理它们。 该图显示通过发布者-订阅者模型进行的请求处理。

显示使用消息中转站处理请求的示意图。

  1. 客户端请求作为消息在消息中转站中排队。

  2. 服务或订阅者轮询中转站,以确定它们是否可以基于其实现的业务逻辑处理该消息。 中转站还可以将消息推送给对该消息感兴趣的订阅者。

  3. 每项订阅的服务都按照消息的指示执行操作,并以操作的成败响应中转站。

  4. 如果成功,服务就可以将消息推送回同一队列或不同的消息队列,以便在需要时另一项服务可以继续执行工作流。 如果操作失败,消息中转站将与其他服务一起使用,以补偿该操作或整个事务。

问题和注意事项

分散编排器可能会导致在管理工作流时出现问题。

  • 处理故障可能具有挑战性。 应用程序中的组件可能会执行原子任务,但它们可能仍有一定程度的依赖性。 一个组件中的失败可能会影响其他组件,这可能会导致完成整个请求延迟。

    为了正常处理故障,实现补偿事务可能会带来复杂性。 故障处理逻辑(如补偿事务)也容易发生故障。

    显示编排模式中错误处理的流程图。

  • 此模式适用于并行处理独立业务操作的工作流。 当编排需要按顺序进行时,工作流程可能会变得复杂。 例如,只有在服务 B 和服务 C 成功完成操作后,服务 D 才能开始操作。

    消息传送系统中的工作流示意图,以并行方式和随后地实现编排模式。

  • 如果服务数量迅速增长,这种模式将成为一项挑战。 考虑到有大量独立的移动部件,服务之间的工作流往往会变得复杂。 此外,分布式跟踪变得困难,尽管 ServiceInsight 以及 NServiceBus 等工具一起有助于降低这些挑战。

  • 在协调器主导的设计中,核心组件可以部分参与并将复原逻辑委托给另一个重试暂时性、非暂时性和超时故障的组件。 随着编排模式中协调器的解散,下游组件不应该承担那些复原任务。 这些操作仍必须由复原处理程序处理。 但现在,下游组件必须直接与复原处理程序通信,从而增加点到点通信。

何时使用此模式

在以下情况下使用此模式:

  • 下游组件独立地处理原子操作。 你可以把它想象成一种“即发即弃”的机制。 组件负责不需要主动管理的任务。 任务完成后,它会向其他组件发送通知。

  • 预计这些组件会经常更新和更换。 该模式允许以更少的工作量和对现有服务的最小干扰来修改应用程序。

  • 此模式非常适合适用于简单工作流的无服务器体系结构。 这些组件可以是短期组件,也可以是事件驱动型组件。 当事件发生时,组件将被启动,执行其任务,并在任务完成后被移除。

  • 对于有界上下文之间的通信,这种模式是一个很好的选择。 对于在单个有界上下文中的通信,可以考虑业务流程协调程序模式。

  • 中央编排器带来了性能瓶颈。

在以下情况下,此模式可能不起作用:

  • 应用程序很复杂,需要一个核心组件来处理共享逻辑,以保持下游组件轻量级。

  • 在某些情况下,组件之间不可避免地存在点对点通信。

  • 需要使用业务逻辑来整合由下游组件处理的所有操作。

工作负荷设计

架构师应评估如何在其工作负荷的设计中使用“协调模式”,以解决 Azure Well-Architected Framework 支柱中涵盖的目标和原则。 例如:

支柱 此模式如何支持支柱目标
卓越运营有助于通过标准化流程和团队凝聚力来实现工作负荷质量 由于此模式中的分布式组件是自治的,并且设计为可替换的,因此可以在对系统进行较少总体更改的情况下修改工作负载。

- OE:04 工具和流程
性能效率通过在缩放、数据和代码方面进行优化, 帮助工作负载高效地满足需求 当集中式业务流程拓扑中出现性能瓶颈时,此模式提供了一种替代方案。

- PE:02 容量规划
- PE:05 缩放和分区

与任何设计决策一样,请考虑对可能采用此模式引入的其他支柱的目标进行权衡。

示例

此示例显示通过创建一个事件驱动的、运行功能和微服务的云原生工作负载的编排模式。 当客户端请求发送一个数据包时,工作负载分配一个无人机。 一旦数据包准备好由预定的无人机提取,交付过程就开始了。 在传输过程中,工作负载处理交付,直到获得已发送状态。

此示例是对 Drone Delivery 实现的重构,该实现将 Orchestrator 模式替换为 Choreography 模式。

事件驱动的云原生示例工作负载实现编排模式的示意图

引入服务处理客户端请求,并将其转换为包含交付详细信息的消息。 业务事务在使用这些新消息之后启动。

单个客户端业务事务需要三个不同的业务操作:

  1. 创建或更新包裹
  2. 分配无人机配送包裹
  3. 处理配送,包括检查并最终在发货时提高意识。

这三项微服务执行业务处理:包裹、无人机计划程序和配送服务。 这些服务不使用中央编排器,而是使用消息传递在它们之间进行通信。 每个服务都将负责提前实现一个协议,以分散的方式协调业务工作流。

设计

业务事务通过多个跃点按顺序进行处理。 每个跃点在所有业务服务之间共享一条消息总线。

当客户端通过 HTTP 终结点发送传递请求时,引入服务会接收该请求,将该请求转换为消息,然后将该消息发布到共享消息总线。 订阅的业务服务将使用添加到总线的新消息。 收到消息后,业务服务可以成功完成操作、失败或者请求可能超时。如果成功,服务将用 Ok 状态代码响应总线,引发新的操作消息,并将其发送到消息总线。 如果出现故障或超时,服务将通过向消息总线发送原因代码来报告故障。 此外,该消息还会添加到死信队列中。 在合理且适当的时间内无法接收或处理的消息也会被移到 DLQ 中。

该设计使用多个消息总线来处理整个业务事务。 Microsoft Azure 服务总线Microsoft Azure 事件网格的组成旨在为此设计提供消息服务平台。 工作负载部署在托管 Azure 功能Azure Container Apps 上以供接收,以及处理执行业务逻辑的事件驱动处理的应用上。

该设计确保编排按顺序进行。 单个 Azure Service Bus 命名空间包含一个具有两个订阅和一个会话感知队列的主题。 引入服务将消息发布到主题。 包裹服务和无人机计划程序服务订阅主题并发布消息,将成功消息传达给队列。 包括一个通用会话标识符(GUID 与传递标识符相关联),支持对相关消息的无界序列进行有序处理。 Delivery 服务为每个事务等待两条相关的消息。 第一条消息表示包已准备好发送,第二条消息表示无人机已安排好。

此设计使用 Azure Service Bus 来处理在整个传递过程中不会丢失或复制的高价值消息。 当包发送时,它还将状态更改发布到 Azure 事件网格。 在这种设计中,事件发送方对如何处理状态更改没有任何期望。 未包含在此设计中的下游组织服务可以侦听此事件类型,并对执行特定业务目的逻辑做出反应(即,将已发送的订单状态通过电子邮件发送给用户)。

如果计划将其部署到另一个计算服务中,如 AKS 发布-订阅模式应用程序样板,可以用同一 pod 中的两个容器来实现。 一个容器运行与首选消息总线交互的大使,而另一个容器执行业务逻辑。 在同一个 Pod 中使用两个容器的方法提高了性能和可伸缩性。 代表和业务服务共享同一网络,该网络允许低延迟和高吞吐量。

为了避免可能导致多次尝试的级联重试操作,业务服务应立即标记不可接受的消息。 可以使用众所周知的原因代码或定义的应用程序代码来丰富此类消息,因此可以将其移动到死信队列 (DLQ) 中。 考虑管理从下游服务实现 Saga 的一致性问题。 例如,另一个服务只能通过执行补偿、重置或 pivot 事务来处理死信消息,以达到修复的目的。

业务服务是幂等的,以确保重试操作不会导致重复资源。 例如,包服务使用 upert 操作将数据添加到数据存储中。

在设计协调时请考虑这些模式。