Service Broker 激活流程包括两个步骤。 首先,Service Broker 确定是否需要激活。 其次,Service Broker 确定是否执行了激活。 尽管内部激活和外部激活的确切过程有所不同,但这两种策略涉及的总体概念是相同的。
确定是否需要激活
只要新队列读取器有要执行的有用工作,就必须进行激活。 队列监视器确定激活是否是必需的。 Service Broker 为每个具有激活 STATUS = ON 或已注册事件通知 QUEUE_ACTIVATION 的队列创建一个队列监视器。 动态管理视图 sys.dm_broker_queue_monitors 列出实例中活动的队列监视器。
每个队列监视器跟踪以下条件:
- 队列是否包含已准备好接收的消息
- 最近队列上的
RECEIVE语句如何返回空结果集 - 队列当前正在运行多少个激活存储过程
队列监视器每隔几秒并且在以下事件中的一个或多个发生时检查激活是否是必需的:
- 新消息到达队列
- SQL Server 为队列执行
RECEIVE语句 - 包含
RECEIVE语句的事务回滚 - 所有由队列监视器启动的存储过程终止
- SQL Server 为队列执行
ALTER语句
如果满足以下任一条件,则需要激活:
新消息到达不包含任何未读消息的队列,并且未为此队列运行激活存储过程。
队列包含未读消息,没有会话正在等待于
GET CONVERSATION GROUP语句或RECEIVE语句中没有WHERE子句,且没有GET CONVERSATION GROUP语句或RECEIVE语句中没有WHERE子句连续几秒钟返回空结果集。 换句话说,当消息在队列上累积时,因为激活的过程无法足够快地读取它们。
实际上,利用此过程,队列监视器可以判断处理队列的队列读取器的数量是否能跟上传入消息的通信流量。 此方法将会话组锁定考虑在内。 由于一次只有一个队列读取器可以为会话处理消息,因此如果因响应更简单的方法(例如,队列中未读消息的数量)而启动队列读取器,则可能会浪费资源。 相反,Service Broker 激活会考虑新的队列读取器是否有有用的工作要做。
例如,队列可能包含单个会话中大量未处理的消息。 在此情况下,只有一个队列读取器可以处理这些消息。 队列监视器激活另一个队列读取器。 第二个队列读取器在 RECEIVE 语句中等待,因为所有消息都属于单个会话。 只要队列中的所有消息都属于同一会话,并且第二个队列读取器仍在运行,队列监视器不会启动另一个队列读取器。
确定是否发生激活
一旦 Service Broker 确定激活是必需的,Service Broker 就必须决定是否发生激活。
对于内部激活,当正在运行的程序数低于 MAX_QUEUE_READERS 为队列设置的值时,队列监视器将激活激活存储过程的新实例。 如果正在运行的程序数等于或大于 MAX_QUEUE_READERS 值,队列监视器不会启动存储过程的新实例。 管理视图 sys.dm_broker_activated_tasks 包含 Service Broker 启动的存储过程的相关信息。
对于外部应用,Service Broker 无法获取可能正在处理队列的不同队列读取器数量的信息。 此外,在引发激活事件的时间和读取器开始读取队列的时间之间,可能需要一些启动时间。 因此,Service Broker 为外部应用程序提供了一个响应超时时间。 在超时期间,Service Broker 不会生成另一个通知。 应用程序调用 RECEIVE 队列或超时过期后,如果需要激活,Service Broker 会创建另一个事件通知。 外部应用程序在程序运行期间监视事件通知,以确定是否需要更多队列读取器来读取事件。