优先级队列模式使工作负荷能够比优先级较低的任务更快地处理高优先级任务。 此模式使用发送到一个或多个队列的消息,在为各个客户端提供不同服务级别保证的应用程序中非常有用。
上下文和问题
工作负荷通常需要管理和处理具有重要性和紧迫性级别不同的任务。 某些任务需要立即处理,而另一些任务可以等待。 未能解决高优先级任务可能会影响用户体验和违反服务级别协议 (SLA)。
若要根据任务的优先级高效地处理任务,工作负荷需要一种机制来相应地确定任务优先级和执行任务。 通常,工作负荷按照任务到达的顺序处理任务,使用先入先出 (FIFO) 队列结构。 此方法不考虑任务的不同重要性。
解决方案
优先级队列允许工作负荷根据任务的优先级而不是到达顺序来处理任务。 向队列发送消息的应用程序会将优先级分配给消息,使用者按优先级处理消息。 满足以下要求时,请使用优先级队列模式:
处理具有不同紧迫性和重要性的任务。 您的任务具有不同紧急程度和重要性,并且需要确保先处理更重要的任务,然后再处理不太重要的任务。
处理不同的服务级别协议。 您需要为客户端提供不同的服务级别保证,并且需要确保高优先级客户端获得更好的性能和可用性。
满足不同的工作负荷管理需求。 您有需要立即处理某些任务的工作量,而不太紧急的任务可以等待。
实现优先级队列模式有两种主要方法:
单个队列:所有消息都发送到一个队列,每个消息都分配有优先级。
多个队列:每个消息优先级使用单独的队列。
单个队列
使用单个队列时,应用程序(生成者)将优先级分配给每个消息,并将消息发送到队列。 队列按优先级对消息进行排序,确保使用者在优先级较低的消息之前处理高优先级的消息。
图 1. 单个队列和单个使用者池的体系结构
多个队列
多个队列允许按优先级分隔消息。 应用程序为每个消息分配优先级,并将消息定向到与其优先级对应的队列。 使用者处理消息。 多个队列解决方案使用单个使用者池或多个使用者池。
多个使用者池
使用多个使用者池时,每个队列都有专用于它的使用者资源。 优先级较高的队列应使用比优先级较低的队列更快地处理消息的使用者或更高的性能层。
如果有以下操作,请使用多个使用者池:
- 严格的性能要求:当不同的任务优先级具有必须独立满足的严格性能要求时,需要多个使用者池。
- 高可用性需求:对于可靠性和故障隔离至关重要的应用程序,需要多个使用者池。 一个队列中的问题不得影响其他队列。
- 复杂应用程序:对于具有需要不同处理特征和性能保证的任务的复杂应用程序,适用于不同的任务。
图 2. 多个队列和多个使用者池的体系结构。
单个使用者池
使用单个使用者池时,所有队列共享单个使用者池。 使用者首先处理来自最高优先级队列的消息,并且仅在没有高优先级消息时处理来自低优先级队列的消息。 因此,单个使用者池始终在优先级较低的消息之前处理更高的优先级消息。 此设置可能会导致优先级较低的消息持续延迟,甚至可能永远不会处理。
将单个使用者池用于:
- 简单管理:单个使用者池适用于易于设置和维护的应用程序,这是一个优先事项。 它降低了配置和监控的复杂性。
- 统一处理需求:当传入任务的确切性质类似时,单个使用者池非常有用。
图 3. 多个队列和单个使用者池的体系结构。
优先级队列模式的建议
在决定如何实现优先级队列模式时,请考虑以下建议:
一般建议
明确定义优先级。 建立与解决方案相关的不同且明确的优先级。 例如,高优先级消息可能需要在 10 秒内进行处理。 确定处理高优先级项的要求,并相应地分配必要的资源。
动态调整使用者池。 根据要维护的队列长度缩放使用者池的大小。
确定服务级别的优先级。 实现优先级队列以满足需要优先可用性或性能的业务需求。 例如,不同的客户组可以接收不同级别的服务,以便高优先级客户体验更好的性能和可用性。
确保低优先级处理。 在支持消息优先级的队列中,如果系统允许它确保低优先级消息最终得到处理,则动态增加过期消息的优先级。
考虑队列成本。 请注意与检查队列相关的财务和处理成本。 某些队列服务会收取发布、检索和查询消息的费用,这些消息可能会随着队列数的增加而增加。
多个队列建议
监控处理速度。 为确保这些消息按照预期速度进行处理,应持续监控高优先级和低优先级队列的处理速度。
尽量降低成本。 利用可用使用者立即处理关键任务。 在不太繁忙的时间安排不太关键的后台任务。
单个使用者池建议
实现抢占和挂起。 决定是否必须在任何低优先级项目之前处理所有的高优先级项目。 使用一种算法,确保在对多个队列使用单个使用者池时,始终在低优先级队列之前为高优先级队列提供服务。
优化成本。 使用单队列方法时,通过缩减使用者数量来优化运营成本。 高优先级的消息首先处理,尽管速度可能较慢,较低优先级的消息可能会面临更长的延迟。
工作负荷设计
架构师应评估优先级队列模式如何实现 Azure Well-Architected Framework 支柱中涵盖的目标和原则。 例如:
支柱 | 此模式如何支持支柱目标 |
---|---|
可靠性设计决策有助于工作负荷在发生故障后复原,并确保它在发生故障后恢复到正常运行状态。 | 根据业务优先级分离项目使你能够将可靠性工作集中在最关键的工作上。 - RE:02 关键流 - RE:07 后台作业 |
性能效率通过在缩放、数据和代码方面进行优化, 帮助工作负荷高效地满足需求。 | 根据业务优先级分离项目使你能够将性能工作重点放在对时间最敏感的工作上。 - PE:09 关键流 |
与任何设计决策一样,请考虑对可能采用此模式引入的其他支柱的目标进行权衡。
优先级队列模式的示例
GitHub 中的以下示例演示了使用 Azure 服务总线 实现优先级队列模式。
图 4. GitHub 中 PriorityQueue 示例的体系结构
以下是体系结构的概述:
应用程序(生成者):该示例有一个应用程序 (
PriorityQueueSender
) 用于创建消息并分配在每个消息中调用Priority
的自定义属性。Priority
的值为High
或Low
。消息中转站和队列:该示例使用 Azure 服务总线作为消息代理。 它使用两个 Azure 服务总线队列,一个用于每个消息优先级(
High
和Low
)。 应用程序(生成者)根据消息Priority
将消息发送到正确的队列。多个使用者池:本示例使用多个使用者池(
PriorityQueueConsumerHigh
和PriorityQueueConsumerLow
)专用于从每个队列读取消息。
示例体系结构中的角色 | 示例中的 Azure 服务 | 示例中的名称 |
---|---|---|
应用程序 | Azure Functions 应用 | PriorityQueueSender |
消息队列中转站 | Azure 服务总线 | <您的服务总线命名空间> |
消息队列 | Azure 服务总线队列 | <您的队列名称> |
使用者 | Azure Functions 应用 | PriorityQueueConsumerHigh PriorityQueueConsumerLow |
相关资源
实现此模式时,以下模式可能有用: