Service Broker 和 AlwaysOn 可用性組:奇怪的傳輸隊列行為
我還在我的部落格上發布了這個問題: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。這種混亂似乎導致每一方都關閉兩個服務之間的現有連接並創建一個新連接以傳遞消息或確認。我不確定這是否正常,或者它是否與為什麼沒有正確處理確認有關,但這是我能看到的唯一可能解釋奇怪行為的東西。
求助請求:
目前,我沒有解決此消息保留問題的方法,只能手動結束雙方的清理對話,而這並不是我真正想做的事情。如果您對為什麼會發生這種情況或我能做些什麼有任何想法,請給我留言並告訴我。如果您希望我提供有關我的設置或問題的任何其他資訊,也請在評論中告訴我。如果/當我找到此問題的解決方案時,我將發布此文章的後續內容。
跟踪數據:
請參閱我的部落格文章(網址在問題的開頭)。
在過去的幾個月中,我一直在與 Microsoft 的產品支持團隊合作,他們已經承認 SQL Server 2012 中與此問題相關的兩個錯誤。作為 SQL Server 2012 下一個服務包的一部分,他們將針對這些錯誤發布更新檔。