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

优先级队列模式

确定发送到服务的请求的优先级,使工作负荷处理高优先级请求的速度比优先级较低的请求更快。 此方法使用发送到一个或多个队列的消息,对于向不同的请求类型或客户提供不同服务级别或服务级别协议(SLA)的应用程序非常有用。

上下文和问题

工作负荷可能需要管理和处理具有不同重要性和紧迫性级别的任务。 某些任务需要立即处理,而另一些任务可以等待。 未能解决高优先级任务可能会影响用户体验和违反 SLA。

若要根据其优先级高效地处理任务,工作负荷需要一种机制来相应地处理和运行任务。 默认情况下,大多数工作负荷按照任务到达的顺序处理任务,使用先出先出(FIFO)队列结构。 此方法不考虑不同的任务重要性。

解决方案

优先级队列允许工作负荷根据其优先级处理任务,而不是严格按其到达顺序处理任务。 发送请求的应用程序或 生成者 向消息分配优先级值, 使用者 按优先级处理消息。 优先级队列模式满足以下要求:

  • 处理具有不同紧迫性和重要性的任务: 任务具有不同级别的紧迫性和重要性,需要确保在不太关键的任务之前处理更多关键任务。

  • 处理不同的 SLA: 你可以为不同的客户提供不同的 SLA,并且需要确保高优先级客户获得更好的性能和可用性。

  • 满足不同的工作负荷管理需求: 你有一个工作负载,需要立即解决某些任务,而不太紧迫的任务可以等待。

实现优先级队列模式有两种主要方法:

  • 单个队列: 为每个消息分配一个优先级值,并且所有消息都使用相同的队列。

  • 多个队列: 为每个消息分配一个优先级值,不同的优先级消息使用单独的队列。

单个队列

在单个队列方法中,应用程序为每个消息分配优先级,并将所有消息发送到单个队列。 队列按优先级对消息进行排序,确保使用者在优先级较低的消息之前处理高优先级的消息。

说明支持消息优先级的排队机制的示意图。

多个队列

多个队列按优先级分隔消息。 应用程序为每个消息分配一个优先级,并将消息定向到与其优先级相对应的队列,使用者在其中处理消息。 多队列解决方案既可以使用单个消费者池,也可以使用多个消费者池。

单个使用者池

在单个池设置中,所有队列共享同一个使用者池。 使用者首先处理来自最高优先级队列的消息,仅当没有更多高优先级消息时,才处理来自低优先级队列的消息。 因此,单个使用者池始终处理优先级较高的消息,然后再处理优先级较低的消息。 此设置可能会导致低优先级消息持续延迟,并且可能永远不会处理。

说明对所有优先级使用单一消费者池的示意图。

出于以下原因,请使用单个使用者池:

  • 简单管理。 如果优先考虑易于设置和维护,请使用单个消费者池。 单个池可降低配置和监视复杂性。

  • 统一的处理需求。 当传入任务的类型类似时,请使用单个使用者池。

多个使用者池

在多个使用者池中,每个队列都有一个专用的使用者池。 优先级较高的队列使用更多的使用者或更高的性能层来更快地处理消息,而不是优先级较低的队列。

该图说明了为每个优先级使用单独的使用者池。

出于以下原因,请使用多个使用者池:

  • 严格的性能要求。 当不同的任务优先级具有必须独立满足的严格性能要求时,请使用多个使用者池。

  • 可靠性高的需求。 当可靠性和故障隔离至关重要时,对应用程序使用多个使用者池,并且一个队列中的问题不得影响其他队列。

  • 复杂应用程序。 对复杂应用程序使用多个使用者池,其中不同的任务需要不同的处理特征和性能保证。

问题和注意事项

在决定如何实现此模式时,请考虑以下几点:

一般建议

  • 明确定义优先级。 建立与解决方案相关的不同且明确的优先级。 例如,可以将高优先级消息定义为需要在 10 秒内处理的消息。 确定处理高优先级项的使用者要求,并相应地分配必要的资源。

  • 动态调整使用者池。 根据消费者池所服务队列的长度调整消费者池的大小。

  • 监控队列健康状况。 跟踪队列深度、处理延迟、交付次数和吞吐量,从而在积压和处理变慢影响工作之前及时发现问题。

  • 使用死信队列。 在可配置数量的传递尝试后,将 有害消息 移动到死信队列,这样一条坏消息就不会阻止优先级路径。

  • 确定服务级别的优先级。 实现优先级队列以满足需要优先可用性或性能的业务需求。 例如,高优先级客户可以接收更高的服务级别,以便他们体验更好的性能和可用性。

  • 考虑低优先级处理。 确定是否必须先处理完所有高优先级项,才能处理任何低优先级项。 如果可能,请动态增加旧消息的优先级,以确保低优先级消息最终得到处理。

  • 优化和降低成本。 利用可用使用者立即处理关键任务。 在不太繁忙的时间安排不太关键的后台任务。

    如果使用单个队列,请通过缩减使用者数量来优化成本。 高优先级消息首先处理,但速度可能更慢,而低优先级消息可能面临更长的延迟。

  • 防止处理器达到需求高峰。 如果生产者到达速率可能超过消费者的处理能力,则可将此模式与基于队列的负载分级模式结合使用。 此方法会缓冲流量突发,并帮助防止下游处理资源过载。

多个队列建议

  • 监控处理速度。 为了确保以预期速率处理消息,请持续监视高优先级和低优先级队列的处理速度。

  • 实现抢占和挂起。 如果将多个队列与单个使用者池一起使用,则实现一种算法,确保高优先级队列始终在低优先级队列之前提供服务。

  • 考虑队列成本。 请注意检查和处理队列所涉及的费用成本。 某些队列服务收取发布、检索和查询消息的费用。 这些费用随着队列数的增加而增加。

何时使用此模式

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

  • 必须满足不同工作类别的不同延迟或服务级别目标,例如高级客户请求与标准客户请求。

  • 工作会成批涌入,你必须优先处理高优先级消息,同时暂缓处理低优先级工作,以保护关键操作。

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

  • 所有工作项都具有类似的业务重要性,严格的 FIFO 处理比基于优先级的计划更重要。

  • 任务具有跨优先级的强排序依赖关系,按优先级重新排序工作可能会导致结果不一致或需要复杂的协调逻辑。

工作负载设计

评估如何在工作负荷的设计中使用优先级队列模式来解决Azure Well-Architected框架支柱中涵盖的目标和原则。 下表提供有关此模式如何支持每个支柱目标的指南。

支柱 此模式如何支持支柱目标
可靠性设计决策有助于让你的工作负载具备抗故障能力,并确保在发生故障后能够恢复到正常运行状态。 根据业务优先级分离项目使你能够将可靠性工作集中在最关键的工作上。

- RE:02 关键流程
通过缩放、数据和代码的优化,性能效率可帮助工作负荷高效地满足需求 根据业务优先级分离事项使你能够将注意力集中在对时间最敏感的任务上。

- PE:09 关键性流程

如果此模式在某个支柱中引入权衡取舍,请将它们与其他支柱的目标进行对比。

示例

GitHub上的优先级队列模式示例演示了使用Azure 服务总线主题和订阅的优先级队列模式的实现。 该示例部署安全存储帐户、用于监视的 Application Insights 资源以及服务总线命名空间,以启用发送方和使用者函数之间的通信。

部署包括三个函数应用:一个发送方和两个使用者。 使用者应用使用不同的最大实例计数来模拟消息优先级。 该 funcPriorityQueueConsumerHigh 函数可以横向扩展到 200 个实例,而函数 funcPriorityQueueConsumerLow 限制为 40 个实例。 所有函数应用都使用 Flex 消耗计划,并连接到 Application Insights 进行诊断和监视。

通过使用托管标识,角色分配可授予对 服务总线 和存储的安全访问权限。 所有函数应用共享相同的存储帐户和 Application Insights 资源。 此配置将可观测性和日志进行统一管理。

下图显示了优先级队列体系结构:

说明如何使用服务总线实现优先级队列的示意图。

在上图中:

  1. 应用程序(生成者)。 PriorityQueueSender应用程序会创建消息,为每条消息分配一个名为Priority的自定义应用程序属性,并将Priority的值设置为HighLow

  2. 消息中转站和主题。 服务总线 消息代理将消息发送到一个名为 messages 的 服务总线 主题。 服务总线 使用 SQL 筛选器根据其 Priority 值,将每条消息路由到高优先级或低优先级订阅。

  3. 多个使用者池。 PriorityQueueConsumerHighPriorityQueueConsumerLow 使用方池通过使用 Azure Functions 服务总线 触发器 来响应来自高优先级或低优先级订阅的消息。

示例中的角色 Azure服务示例 示例中的名称
应用程序(生成者) Azure Functions 应用 PriorityQueueSender
消息代理 Azure 服务总线 <你的服务总线命名空间>
消息主题 Azure 服务总线 主题 messages
消息订阅 Azure 服务总线订阅 highPriority
lowPriority
使用者 Azure Functions 应用 PriorityQueueConsumerHigh
PriorityQueueConsumerLow

后续步骤

实现此模式时,以下模式可能很有用:

  • Queue-Based 负载调配模式:在请求引入和处理之间使用队列作为缓冲区。 需要突发保护和区分处理时,将其与优先级队列模式配合使用。

  • 竞争性消费者模式:使用多个消费者监听同一队列,并并行处理任务,以提高吞吐量。 每条消息只有一个使用者处理。

  • 限制模式:使用队列管理请求速率来实现限制。 使用优先级消息传送将关键应用程序或高价值客户的请求优先于不太重要的请求。