我还在我的博客上发布了这个问题:http ://www.sqldiablo.com/2012/04/15/service-broker-alwayson-availability-groups-odd-transmission-queue-behavior/ 。
在过去的几个月里,我一直在从事一个项目,该项目将利用 Service Broker 和 AlwaysOn 可用性组来满足我工作的公司的一些 HA 和 DR 目标(更多信息:)http://www.sqldiablo.com/service-broker-replication/
。就在最近,我能够在我的开发实验室中实施完整的解决方案,并将我们网站的一个实例指向它。当我们在我们的数据库和网站中解决一些问题以使这两者与我的 Service Broker Replication 项目一起正常工作时,我开始注意到 Service Broker 在与 AlwaysOn 可用性组一起使用时出现了一些奇怪的行为,我想在博客中介绍它试图看看其他人是否已经看到了这个问题,并且可能知道如何解决它。
设置:
我有一台运行 6 个 Windows Server 2008 R2 VM (BTDevSQLVM1-BTDevSQLVM6) 的 Hyper-V 主机。VM 被分组为具有节点和文件共享仲裁的 2 节点 WSFC。我在每个 VM 上安装了独立的 SQL 2012 Developer Edition 实例,并在每个集群(SBReplDistrib、SBRepl1 和 SBRepl2)上创建了一个带有侦听器的可用性组。
出于这篇博文的目的,我将重点关注 SBRepl1 和 SBReplDistrib 之间的通信。下图显示了对话每一方的 Service Broker 对象:
(我是新手,还不能发布图片,所以请在上面的 URL 中查看我的博客以获取图片)
Service Broker 端点和路由是根据这篇 MSDN 文章设置的。MSDB 中的 SBRepl_Receive 路由用于本地服务器的服务(SBReplDistrib 上的//SBReplDistrib/SBRepl,SBRepl1 上的//SBRepl1/SBRepl),并指向本地实例。SBRepl1 上的 SBRepl_Send 路由将服务 //SBReplDistrib/SBRepl 映射到 TCP://SBReplDistrib:4022,SBReplDistrib 上的 SBRepl_Send_SBRepl1 路由是 SBRepl1 上服务的类似映射。
预期行为:
因此,我对 Service Broker 如何处理消息发送和接收的理解是(这非常简化。在 Klaus Aschenbrenner 的书“Pro SQL Server 2008 Service Broker”中有更多关于此过程的详细信息):
- 发起者应用程序创建一条消息(在这种情况下,格式正确的 XML)
- 如果发起者服务和处于会话状态的目标服务之间存在现有对话对话,则应用程序可以简单地在现有对话句柄上发送消息。否则,发起者应用程序应该开始发起者服务和目标服务之间的对话对话,并在该对话句柄上发送消息。
- 消息放置在 sys.transmission_queue 系统表中,Service Broker 开始尝试将消息传递到目标服务。
- Service Broker 查找适当的路由和远程服务绑定,并使用它们来确定要连接的地址以传递消息。
- Service Broker 打开与目标的连接,进行身份验证并将消息传递给目标服务代理。
- 目标 Service Broker 尝试对消息进行分类并确定哪个本地服务将处理该消息(为此,它使用 msdb 数据库中的路由数据)。
- 目标服务代理将消息传递到目标服务的队列
- 一旦消息成功传送到目标队列,目标 Service Broker 将查找路由信息返回给发起方,并尝试传送已收到消息的确认。
- 发起方的 Service Broker 接收确认并使用 MSDB 中的路由信息来确定确认的本地服务。
- 在将确认成功路由到启动服务后,该消息将从 sys.transmission_queue 系统表中删除。
- 如果发起者没有收到收到消息的确认,它将定期重试将消息传递给目标。如果目标已经收到消息,它将简单地放弃任何额外的传递重试并为它们发送确认。
奇怪的行为:
第 11 步是我看到 Service Broker 和 AlwaysOn 的一些非常奇怪的行为。我看到消息被传递到目标并成功处理,我还看到确认被发送回发起者并被接收。但是,该消息仍保留在 sys.transmission_queue 中,就好像没有收到任何确认一样。更奇怪的是,如果没有收到确认,Service Broker 并没有像我期望的那样尝试重新发送消息。相反,消息只是保留在 sys.transmission_queue 中,并且随着新消息的发送,它们会被传递、确认,并且它们也保留在 sys.transmission_queue 中。在我看来,服务代理正在获得确认,因此停止尝试传递消息,但不会将其从 sys.path 中删除。由于某种原因传输队列。这些消息的传输状态保持空白,这表明 Service Broker 尚未尝试传递它们。
我检查了服务队列上的保留设置,它被设置为关闭,但这只会影响服务队列而不是 sys.transmission_queue。我还使用 SQL Profiler 跟踪了对话的双方,我能够看到消息被发送,确认被发送回发起者并被接收(请参阅本文末尾的 XML 跟踪数据)。
不过,一件奇怪的事情确实在我身上跳出来了。我注意到双方似乎对 TCP 连接有点困惑,因为消息是从节点本身的 IP 地址发送的,而服务路由和消息本身指向 AG 侦听器的名称/IP。这种混乱似乎导致每一方都关闭两个服务之间的现有连接并创建一个新连接以传递消息或确认。我不确定这是否正常,或者它是否与为什么没有正确处理确认有关,但这是我能看到的唯一可能解释奇怪行为的东西。
求助请求:
目前,我没有解决此消息保留问题的方法,只能手动结束双方的清理对话,而这并不是我真正想做的事情。如果您对为什么会发生这种情况或我能做些什么有任何想法,请给我留言并告诉我。如果您希望我提供有关我的设置或问题的任何其他信息,也请在评论中告诉我。如果/当我找到此问题的解决方案时,我将发布此帖子的后续内容。
跟踪数据:
请参阅我的博客文章(网址在问题的开头)。