会话优先级

会话优先级是一组用户定义的规则,每个规则分别指定一个优先级别以及用于确定哪些 Service Broker 会话分配该优先级别的条件。通常,先发送或接收优先级别较高的会话的消息,再发送或接收优先级别较低的会话的消息。

会话优先级的用途

会话优先级可用于执行以下操作:

  • 标识会话是否优先于其他会话。

  • 支持不同的服务层,其中,支付较高价格的客户的消息先发送,支付较低价格的客户的消息后发送。

  • 优先处理客户请求而非后台任务。例如,新客户注册应比向数据仓库发送业务事务摘要具有更高的优先级。

会话优先级与会话端点

会话优先级是使用 CREATE BROKER PRIORITY 语句在每个数据库中创建的。每个会话优先级均定义了以下内容:

  • 会话优先级的名称。

  • 分配给 Service Broker 会话的优先级别。该级别被指定为从 1(最低)到 10(最高)的整数。默认值为 5。

  • 用于确定优先级别应用于哪些会话的条件如下:

    • 约定名称或 ANY。

    • 本地服务名称或 ANY。

    • 远程服务名称或 ANY。

Service Broker 在创建会话端点时为其分配优先级别。每个会话均有两个会话端点:

  • 发起方会话端点将会话的一端与发起方服务和发起方队列相关联。发起方会话端点是在运行 BEGIN DIALOG 语句时创建的。与发起方会话端点关联的操作包括:

    • 从发起方服务发送。

    • 从发起方队列接收。

    • 从发起方队列获取下一个会话组。

  • 目标会话端点将会话的另一端与目标服务和队列相关联。目标会话端点是在将来自发起方的第一个消息放入目标队列时创建的。与目标会话端点关联的操作包括:

    • 从目标队列接收。

    • 从目标服务发送。

    • 从目标队列获取下一个会话组。

哪个服务被认定为本地或远程服务取决于会话端点的类型:

  • 对于发起方会话端点,发起方服务为本地服务,目标服务为远程服务。

  • 对于目标会话端点,目标服务为本地服务,发起方服务为远程服务。

Service Broker 如何分配优先级别

Service Broker 在创建会话端点时分配会话优先级别。会话端点将优先级别一直保留到会话结束。新的优先级或对现有优先级的更改都不会应用于现有会话。

Service Broker 将约定和服务条件与端点属性最匹配的会话优先级中的优先级别分配给会话端点。下表显示了匹配优先顺序:

端点约定

端点本地服务

端点远程服务

优先级约定

优先级本地服务

优先级远程服务

优先级约定

优先级本地服务

ANY

优先级约定

ANY

优先级远程服务

优先级约定

ANY

ANY

ANY

优先级本地服务

优先级远程服务

ANY

优先级本地服务

ANY

ANY

ANY

优先级远程服务

ANY

ANY

ANY

Service Broker 首先寻找其指定的约定、本地服务和远程服务与会话端点所用的约定、本地服务和远程服务匹配的优先级。如果找不到,Service Broker 将接着寻找约定和本地服务与端点所用的约定和本地服务匹配且远程服务被指定为 ANY 的优先级。此过程会一直继续下去,直到优先顺序表中列出的所有变体均已比对过为止。如果未找到匹配项,将为端点分配默认优先级 5。

Service Broker 通信协议不在会话端点间传输优先级别。Service Broker 独立地为每个端点分配一个优先级别。若要让 Service Broker 将优先级别同时分配给发起方会话端点和目标会话端点,必须确保会话优先级同时涵盖这两个端点。如果发起方会话端点和目标会话端点分别在不同的数据库中,则必须在每个数据库中创建会话优先级。如果发起方端点和目标端点在同一个数据库中:

  • 可以使用一个会话优先级同时涵盖两个会话端点,该会话优先级要指定会话所用的约定名称并为本地和远程服务名称均指定 ANY。

  • 可以使用两个会话优先级分别涵盖每个会话端点:

    • 一个针对发起方端点的会话,为 LOCAL_SERVICE_NAME 指定发起方服务名称,并为 REMOTE_SERVICE_NAME 指定目标服务名称。

    • 一个针对目标端点的会话,为 LOCAL_SERVICE_NAME 指定目标服务名称,并为 REMOTE_SERVICE_NAME 指定发起方服务名称。

通常为会话的两个会话端点指定相同的优先级别。尽管可以为每个端点指定不同的优先级别,但这样做并不意味着某个方向的消息发送速度会比另一个方向快。消息从一个会话端点发出,在另一个端点上接收。因此,每次消息传输都会受到分配给这两个端点的优先级别的影响。例如,您可以配置一个会话,使发起方会话端点的优先级别为 10,而目标端点的优先级别为 1。在这种情况下:

  • 消息从发起方服务传输时使用优先级别 10,从目标队列接收时使用优先级别 1。

  • 消息从目标服务传输时使用优先级别 1,从发起方队列接收时使用优先级别 10。

在以下情况下,分配给会话组的优先级别与分配给任意会话的最高优先级别相同:

  • 会话是组的成员。

  • 会话当前在服务队列中拥有消息。

如果未在数据库中创建任何会话优先级,将为数据库中的所有会话端点分配默认优先级 5。

会话优先级不会影响消息转发,消息转发总是采用默认优先级 5。

会话优先级示例

假定系统配置如下:

  • 一个 InitiatorDB,其中包含 InitiatorServiceInitiatorQueue

  • 一个 TargetDB,其中包含 TargetServiceTargetQueue

  • 一个名为 SimpleContract 的约定,指定将 RequestMessagesInitiatorService 发送到 TargetService。它还指定将 ReplyMessagesTargetService 发送到 InitiatorService

此脚本指定发起方会话端点的优先级别及其关联操作:

  • RequestMessageInitiatorService 发送到 TargetQueue 的 SEND。

  • InitiatorQueue 接收 ReplyMessage 的 RECEIVE。

USE InitiatorDB;
GO
CREATE BROKER PRIORITY InitiatorToTargetPriority
    FOR CONVERSATION
    SET (CONTRACT_NAME = SimpleContract,
         LOCAL_SERVICE_NAME = InitiatorSerivce,
         REMOTE_SERVICE_NAME = N'TargetService',
         PRIORITY_LEVEL = 3);
GO

此脚本指定目标会话端点的优先级别及其关联操作:

  • TargetQueue 接收 RequestMessage 的 RECEIVE。

  • ReplyMessageTargetService 发送到 InitiatorQueue 的 SEND。

USE TargetDB;
GO
CREATE BROKER PRIORITY TargetToInitiatorPriority
    FOR CONVERSATION
    SET (CONTRACT_NAME = SimpleContract,
         LOCAL_SERVICE_NAME = TargetService,
         REMOTE_SERVICE_NAME = N'InitiatorService',
         PRIORITY_LEVEL = 3);
GO

优先级的工作方式

通常,Service Broker 先发送和接收高优先级会话的消息,再发送和接收低优先级会话的消息。高优先级会话的消息在队列中等待的时间短于低优先级会话的消息。

接收优先级别

优先级别总是应用于从队列接收消息或会话组标识符的操作。

优先级别是确定 RECEIVE 应检索哪一组消息以及消息检索顺序的因素之一:

  • 每个 RECEIVE 语句总是检索来自一个会话组的消息:

    • 不含 WHERE 子句的 RECEIVE 语句检索优先级最高并有消息在队列中的未锁定会话组的消息。

    • 含有 WHERE 子句的 RECEIVE 语句检索在 WHERE 子句中指定的会话组的消息。

  • 在会话组中,RECEIVE 根据组中会话的优先级别来检索消息。首先检索具有最高优先级别的会话的所有消息,其次检索具有第二高优先级别的会话的消息,依此类推。

  • 在会话中,消息的检索顺序与消息的发送顺序相同。

GET CONVERSATION GROUP 从一组在队列中拥有消息的未锁定会话组中返回优先级别最高的组。

传输优先级别

一个实例的传输队列中的消息按照以下顺序传输:

  • 与其关联的会话端点的优先级别。

  • 在优先级别内,依照其在会话中的发送顺序。

Service Broker 跨数据库引擎实例中的所有传输队列协调优先级别。Service Broker 先传输所有传输队列中优先级别为 10 的会话的消息,再传输优先级别为 9 的会话的消息,依此类推。

优先级别间的差异越大,消息传输性能的相对差异也越大。在采用两个相邻优先级别(如 9 和 10)的系统中,优先级别较高的消息仅具有较小的性能优势。在采用两个相差很大的优先级别(如 1 和 10)的系统中,优先级别较高的消息将具有较大的性能优势。在使用多个优先级别的系统中,大部分处理资源都将分配给前两个或前三个优先级别。

如果将 HONOR_BROKER_PRIORITY 数据库选项设置为 ON,则会话优先级中指定的优先级别仅应用于传输队列中的消息。如果 HONOR_BROKER_PRIORITY 设置为 OFF,将使用默认优先级 5 发送放入该数据库传输队列内的所有消息。使用 sys.transmission_queue 查看消息时,消息仍显示它从端点接收的优先级,而默认优先级用来传输消息。

由于优先级别应用于传输队列中的消息,因此一般不会影响在同一个数据库引擎实例的服务间发送的消息。发送到相同实例中的服务的消息被直接放入该服务的队列中,而不会先放入传输队列中。某些情况可能会导致本地消息被放入传输队列中,比如出现了某些类型的错误或目标队列处于非活动状态。如果将消息存储在传输队列中,将应用相关的优先级别。

消息和消息片段可能不会按优先级顺序进行发送:

  • Service Broker 使用消息片段块在数据库引擎实例之间发送消息。如果有一些优先级不同的消息片段准备发送到某个实例,Service Broker 可能会在一个块中发送所有片段。位于该块末端的某些消息片段的优先级别可能低于等待传输给其他实例的消息片段。

  • Service Broker 中包含一个“饥饿”防范机制,以防止大量高优先级消息阻塞低优先级消息。即便队列中仍存在优先级较高的消息,也会发送已等待较长时间的低优先级消息。

虽然个别消息或消息片段可能不会按优先级顺序进行发送,但考虑到所发送的消息量庞大,其影响不会太大。