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 协议层处理两个 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 网络。
Service Broker 消息处理
Service Broker 使用两种完全不同的消息类别。 “已编序的消息”是必须按照顺序传递给应用程序的消息,且该消息只能传递给应用程序一次。 “未编序的消息”是可以立即处理的消息,不必考虑其到达的顺序。
Service Broker 对所有用户定义消息类型、结束对话消息和应用程序创建的错误消息使用已编序的消息。 每个已编序的消息都有一个序列号。 发起消息的实例创建消息序列号并将该序列号分配给消息。 接收 Broker 使用消息序列号对它向应用程序提供的消息进行排序。 对于给定的对话,应用程序总是首先接收序列号最低的消息。 Service Broker 还使用消息序列号来检测重复消息。 当对话协议层对同一对话收到两个序列号相同的消息时,对话协议层认为这两个消息是重复的并会放弃其中的一个。
Service Broker 对由 Service Broker 创建的专用确认消息和错误消息使用未编序的消息。 Service Broker 传递未编序的消息时不采取任何特殊的预防措施。 但是,Service Broker 会创建未排序的消息以响应传入消息。 因此,如果未编序的消息丢失,发送方将重试发送原始消息;接收方则会生成另一个未编序的消息。
消息碎片
Service Broker 将传出消息拆分成若干片段,然后再将传入的片段组合成原始消息。 对于小消息,整个消息包含在一个片段中。 对于大消息,Service Broker 将创建多个片段。
将消息分段有几个优点。 当通过速度相对较低和可靠性相对较差的网络(如广域网 (WAN))进行通信时,使用小片段发送大消息可以改善整体速度和可靠性。 如果消息的某个片段丢失,则该协议只需重新传输这一个片段而不是整个消息。 通过对大消息进行分段,还可以减少小消息到达目标所需的时间。 Service Broker 可以在大消息的片段之间发送包含完整小消息的片段。 这样虽然会使大消息的传输速度稍稍减慢,但会缩短小消息等待传输的时间。
当消息进行重组时,部分消息存储在目标队列中。 如果目标队列不可用,则存储在传输队列中。 应用程序无法接收部分消息。 部分 status 消息的列设置为 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 网络通信的概要视图。
会话是一个持久性的逻辑连接。 会话可以持续任意长短的时间,在这段时间内,会话可以使用任意数量的网络连接。
网络连接发生在两个 Service Broker 端点之间。 这些连接使用 TCP/IP。 如果在一小段时间内连接处于不活动状态,Service Broker 将关闭该网络连接。
为了传递消息,Service Broker 将消息保存在发送该消息的数据库的传输队列中。 接收方将该消息直接传递到目标服务的队列中。 如果该队列是 OFF,则消息暂时保存在接收数据库的传输队列中。 发送服务的队列不涉及该作。 仅当目标队列为时,才会涉及承载接收服务的数据库的传输队列 OFF。