Service Broker 通信协议

Service Broker 使用特定于 Broker 的协议与远程 Broker 进行通信。Broker 将这些连接与普通客户端连接池分开管理。为使两个 SQL Server 实例能够交换 Service Broker 消息,每个实例都必须能够向另一个实例所使用的 Service Broker 通信端口发送 TCP/IP 通信。根据约定,Service Broker 通常使用端口 4022 进行 Broker 间通信。但是,最终使用的端口是在创建端点时指定的。

协议层

Service Broker 采用分层的方法进行通信。每一层都建立在下面一层之上以帮助确保可靠的消息传递。此方法使应用程序在不知道远程服务的位置或 Broker 用于通信的物理传输的情况下,仍可正常运行。在大多数情况下,这些协议对应用程序都是透明的。但是,了解每个协议层所起的作用有助于在应用程序出现问题时排除故障。

“对话协议”是 Broker 所用的最高层的协议。对话协议层处理可靠的、已编序的消息传输。对话协议层生成消息的序列号、生成确认消息、向正确的队列传递消息并对消息进行分段和重组。对话协议处理对话的身份验证和加密。

对话协议使用“相邻 Broker 协议”传输消息片段。相邻 Broker 协议处理在两个 Broker 实例间交换的网络传输。

相邻 Broker 协议使用“传输协议”(如 TCP/IP)将消息从一个 Broker 传递到另一个 Broker。

对话协议

对话协议管理会话中消息的一次顺序 (EOIO) 传递模式。此协议不描述 Service Broker 消息在网络上所使用的格式。而是指定建立一个可靠的会话所需的逻辑步骤。对话协议处理进行可靠传递所需的任务,包括生成和处理确认消息。

会话的每一方都是对话协议层中的一个端点。目录视图 sys.conversation_endpoints 显示有关对话协议端点的信息。会话端点在整个会话生存期都存在。

相邻 Broker 协议

相邻 Broker 协议层处理两个 SQL Server 实例间的通信机制。此层将每个消息片段编码为适合在网络上传输的标准格式。与对话协议层不同,相邻 Broker 协议层知道所用的网络传输和相应的消息片段格式。实际上,相邻 Broker 协议层在对话协议层和传输协议层之间提供了一个抽象层。

每个 Service Broker 网络连接都是该相邻协议层中的一个端点。动态管理视图 sys.dm_broker_connections 显示有关 Service Broker 网络连接的信息。Service Broker 在消息交换期间维护网络连接。如果在一小段时间内,没有任何消息通过该网络连接进行发送或接收,Service Broker 将关闭该网络连接。

传输协议

传输协议层处理实际的网络传输。此层位于 Service Broker 之外。例如,发送给在另一个 SQL Server 实例中运行的 Broker 的消息使用 TCP/IP 作为传输协议层。

Service Broker 端点为传输协议设置选项。默认情况下,SQL Server 不包含 Service Broker 端点。有关创建 Service Broker 端点的详细信息,请参阅 如何激活 Service Broker 网络 (Transact-SQL)

Service Broker 消息处理

Service Broker 使用两种完全不同的消息类别。“已编序的消息”是必须按照顺序传递给应用程序的消息,且该消息只能传递给应用程序一次。“未编序的消息”是可以立即处理的消息,不必考虑其到达的顺序。

Service Broker 对所有用户定义的消息类型、结束对话消息和应用程序创建的错误消息使用已编序的消息。每个已编序的消息都有一个序列号。发起消息的实例创建消息序列号并将该序列号分配给消息。接收 Broker 使用消息序列号对它向应用程序提供的消息进行排序。对于给定对话,应用程序始终最先接收序列号最小的消息。Service Broker 还使用消息序列号检测重复的消息。当对话协议层对同一对话收到两个序列号相同的消息时,对话协议层认为这两个消息是重复的并会放弃其中的一个。

Service Broker 对 Service Broker 创建的专用确认消息和错误消息使用未编序的消息。Service Broker 传递未编序的消息时不采取任何特殊的预防措施。但是请注意,Service Broker 会创建未编序的消息来响应传入消息。因此,如果未编序的消息丢失,发送方将重试发送原始消息;接收方则会生成另一个未编序的消息。

消息片段

Service Broker 将传出消息拆分成若干片段,然后再将传入的片段组合成原始消息。对于小消息,整个消息包含在一个片段中。对于大消息,Service Broker 将创建多个片段。

将消息分段有几个优点。当通过速度相对较低和可靠性相对较差的网络(如广域网 (WAN))进行通信时,使用小片段发送大消息可以改善整体速度和可靠性。如果消息的某个片段丢失,则该协议只需重新传输这一个片段而不是整个消息。将大消息分段还可以缩短小消息到达目标所需的时间。Service Broker 可以将包含整个小消息的片段夹杂在大消息的片段间发送。这样虽然会使大消息的传输速度稍稍减慢,但会缩短小消息等待传输的时间。

当消息进行重组时,部分消息存储在目标队列中。如果目标队列不可用,则部分消息存储在传输队列中。应用程序无法接收部分消息。部分消息的**“状态”**列设为 2(禁用)。此值还可用于收到的顺序不对的消息。

消息确认

Service Broker 会确认收到的每条消息。一条确认可以确认一个或多个消息片段。如果可能,确认将包含在同一会话的返回消息的标头中。如果没有其他准备要发送的消息,则 Service Broker 会返回一个专用确认消息。消息确认完全由 Service Broker 处理;使用 Service Broker 的应用程序不接收这些消息。

发送方保留接收方未确认的消息片段。如果在系统定义的等待时间内没有收到确认,发送方将再次发送该消息片段。如果在等待时间内没有收到确认,则在下次重试前,Service Broker 按指数规律延长等待时间,最多延长到最长等待时间。重试的初始等待时间只有几秒。最长等待时间大约为一分钟。请注意,等待时间不一定非常精确;根据网络通信流量和 SQL Server 实例中的其他活动,消息片段在等待时间过期后的几秒内可能不会重试发送。

如果某个确认丢失或延迟,接收方可能会收到重复的消息。在这种情况下,接收方确认收到重复的消息,但不会将重复的消息传递到队列中。

Service Broker 使用消息确认在没有分布式事务的情况下提供可靠的消息传递。接收方仅在向队列添加消息或消息片段后才发送确认。发送方在传输队列中将消息一直保存到该消息的确认到达为止。尽管发送方和接收方从不共享事务,但协议可以保证发送方不会在接收方成功收到消息前从传输队列中删除该消息。

消息完整性检查

Service Broker 用于传输消息的格式包含消息完整性检查,以确定给定消息在传输过程中是否已更改或损坏。

消息完整性检查是消息内容的 MD5 签名。SQL Server 使用消息的会话密钥加密该签名,并将该签名包含在消息标头中。

消息的目标解密该消息,然后将消息中的签名与对实际接收内容进行计算得出的新签名进行比较。如果这两个签名不相符,则该消息在传输过程中已损坏或被篡改。该消息未通过消息完整性检查。SQL Server 将放弃该消息,也不会向发送方确认该消息。当某个消息未能通过消息完整性检查时,Broker:Corrupted Message 事件类将报告有关信息。

Service Broker 传输对象

Service Broker 传输对象是一种内存中的对象,用于管理和记录对话的消息传输状态。每个会话端点都有一个传输对象。

对话在执行下列操作时请求传输对象:

  • 通过传输队列发送消息。其中包括:

    • 发送到数据库引擎的远程实例的所有消息

    • 发送到本地实例中的队列的消息(如果无法将消息直接插入目标队列)

  • 接收远程消息或来自本地传输队列的消息。

当对话首次请求传输对象时,将创建一个传输对象。Service Broker 将为该对话的后续请求使用该传输对象。每当 Service Broker 必须在对话的消息传输状态中记录更改时,都会修改传输对象。传输对象约为 1 KB。

为了释放内存,Service Broker 会定期将成批的非活动传输对象存储在 tempdb 工作表中。当第一次在内存中修改传输对象时,会将该对象标记为“脏”。在刷新到工作表之前,该传输对象将一直标记为“脏”。

传输对象不用于发送或接收可直接插入目标队列的本地消息。

网络通信流

下图显示的是两个 SQL Server 实例间的 Service Broker 网络通信的高级视图。

两个实例之间的 Broker 网络通信

请注意,会话是一个持久的逻辑连接。会话可以持续任意长短的时间,在这段时间内,会话可以使用任意数量的网络连接。

网络连接发生在两个 Service Broker 端点之间。这些连接使用 TCP/IP。如果在一小段时间内连接处于不活动状态,SQL Server 将关闭该网络连接。

为了传递消息,Service Broker 在发送该消息的数据库的传输队列中保存该消息。接收方将该消息直接传递到目标服务的队列中。如果该队列设为 OFF,则消息将临时保存在接收数据库的传输队列中。该操作中不涉及发送服务的队列。如果目标队列设为 OFF,则只涉及接收服务所驻留数据库的传输队列。

请参阅

概念