Sql-Server

服務代理 - 對話終生?

  • February 2, 2021

我們正在嘗試讓 Service Broker 在我們的環境中工作以解決業務案例。我不知道消息標題是否好,但我的問題如下。但這可能不是一個好問題,所以這就是我們正在做的事情以及為什麼我認為這是一個正確的問題。

在結束對話之前,應該在對話中發送多少條消息?

我們想使用 Service Broker 來非同步更新結果表。結果表扁平且快速。我們在基表上有觸發器,它們使用它們的表和主鍵發送消息。我們有三個隊列:

  • 低延遲 - 目標是 15 秒處理。它處理與特定項目相關的更改項目。
  • 批量隊列 - 目標是 5 分鐘處理。它會處理影響數百(或數千)項的更改。它分解了受影響的項目列表並將它們提供給延遲低延遲隊列。
  • 延遲低延遲 - 目標是處理 30 分鐘。這會處理項目,但僅來自批量隊列。

基本上,如果客戶的資訊更新,這會影響許多產品,因此會被發送到批量隊列以減慢處理速度。但是,如果產品得到更新,則會被發送到低延遲隊列。

我們重複使用類似於 Remus Rusanu 的部落格http://rusanu.com/2007/04/25/reusing-conversations/的對話,不同之處在於我們基於主鍵的模數來做。這具有輔助主鍵重複數據刪除的附帶好處。

因此,我們正在重複使用對話,並且在我們的指導方針之內。使用兩個執行緒,我能夠通過 125 條消息/秒(人工丟棄數千條消息),這足以跟上生產(估計 15 條消息/秒)。

但是,我們遇到的問題是,經過一段時間(約 4 小時或 120K 條消息)後,我們開始在 sysdesend 和隊列表上看到塊和高度爭用。鎖是 LCK_M_U 並且是 KEY 鎖。有時 hobt 解析為 sysdesend,有時解析為特定的隊列表 (queue_)。

我們有一個流程可以在 24 小時或 30 分鐘不活動後結束對話,我們可以增加對話循環之前的時間。

我們正在使用 SQL 2016 Enterprise (13.0.4001.0)

  1. 觸發觸發(發送到低延遲或批量)
  2. 查找或創建對話句柄。
  3. 發資訊
  4. 隊列啟動程序
  5. 更新結果表

清理過程每 10 分鐘執行一次,以查看是否有任何空閒對話。ltd 它連續找到它們超過 3 次,將其標記為非活動並結束對話。

如果有任何其他可能有益的細節,請告訴我。我對 Service Broker 沒有太多經驗,所以我不知道我們的消息/秒是低、高還是無關緊要。

更新

所以我們今天又試了一次,遇到了同樣的問題。我們將對話生命週期更改為 2 小時,但沒有任何效果。所以我們然後實施了 150 技巧,它有同樣的問題。

在 SEND CONVERSATION 上等待大量等待,在 sysdesend 上等待。有沒有人有任何進一步的想法?

更新 2

今天我們執行了更長時間的測試,在其中一個 17 分鐘的樣本時間段內,我們在 4 個對話句柄上處理了 41K 條消息。我們能夠跟上,除了接近尾聲時 sysdesend 和隊列表上的鎖變得太多,我們在停止它之前開始落後。我們似乎在處理消息時沒有問題,沒有東西進入隊列:我們可以將它們拉下來並以至少 5 倍的速度處理它們。基於添加消息,我們的速度似乎受到限制。

在後來的測試中,我們刪除了佔消息的 80% 的觸發器之一。即使負載大大減少,我們也開始看到相同的等待。

更新 3

謝謝你,Remus 的建議(也感謝你發布關於這個主題的如此優秀的部落格文章,它們有助於達到這一點)。

我們今天再次執行它並且做得更好(因為我們在看到等待之前走了更長的時間,甚至在它使我們癱瘓之前更長時間)。所以,細節。

我們改變了:

  • 將每個執行緒維護的對話數量從 1:1 增加到 2:1。基本上,我們有 4 個執行緒的 8 個對話句柄。
  • 合併批量隊列(因為一條傳入消息可能意味著數百條傳出消息)以合併為更少、更大的消息。

關於此嘗試的注意事項:

  • 禁用目標隊列啟動過程。阻塞沒有變化(我們等了 5 分鐘),消息確實被發送到了 sys.transmission_queues。
  • 監控 sys.conversation_endpoints。這個數字非常迅速地從 0 變為 13K,然後全天緩慢上升,大約 5 小時後最終達到 25K。阻塞直到達到 16K+/- 才開始發生
  • 我進入 DAC 並為隊列執行 DBREINDEX 命令,儘管從查詢中發現,在清理出現並將計數降至 0 之前,幽靈記錄從未超過 200 條左右。
  • 當我結束測試時,sysdesend 和 sysdercv 的計數相同,均為 24,932。
  • 我們在 5 小時內處理了約 31 萬條消息。

在事情崩潰之前我們已經走了這麼遠,以至於我真的認為這次我們會成功。明天我們將嘗試強制消息通過線路。

我知道回答你自己的問題是不好的形式,但我想為任何感興趣的人關閉這個。我們終於設法解決了這個問題,或者至少解決了它足以滿足我們的要求。我要感謝所有提供意見的人;Remus Rusanu 和 Kin,因為他們非常樂於助人。

我們的數據庫非常繁忙並且處於 RCSI 模式。我們有多個(數千個)移動設備每 45 秒更新一次位置資訊。通過這些更新,多個表的資訊得到更新(糟糕的設計,因為我會將易失性資訊限制在單個表中,然後將其加入以獲得結果)。這些表與我們試圖為其非同步生成報告資訊的表相同,而不是讓最終使用者直接訪問基表。

我們最初讓觸發器在每個更新/插入語句(在大多數情況下應該是一行)中對修改的記錄進行游標,並將消息中的每個主鍵發送到服務代理。在服務代理內部,尤其是批量隊列是進一步的游標,它們執行報告的 upsert 過程(每個主鍵執行一次)。

是什麼最終讓我們工作:

  • 我們刪除了游標並決定發送更大的消息。每個表每個使用者事務仍然有一條消息,但我們現在發送帶有多個主鍵的消息。
  • 批量處理器還為每條消息發送多個密鑰,這減少了在適當時將消息混洗到另一個隊列時正在進行的 SEND CONVERSATIONS 的數量。
  • 最不穩定的表(我們的移動設備數據表)刪除了它的觸發器。我們更新了 upsert 過程以包含適當的外鍵,現在我們只需在向使用者獲取結果時加入該表。該表輕鬆貢獻了我們一天必須處理的 80% 的消息。

我們每天處理約 100 萬條消息(沒有 Mobile 表),並且絕大多數 (99%+) 消息都在我們的目標內處理。我們仍然有偶爾的異常值,但考慮到它被認為是可以接受的罕見性質。

影響因素:

  • 我在前面提到的對話清理過程中發現了一個錯誤,它實際上並沒有適當地清理對話,而是過早地結束了它們。現在這導致我們的 sysdesend 計數永遠不會超過幾千(其中大部分來自使用 150 技巧)。
  • 觸發器中的游標似乎持有比預期更多的鎖定(即使是靜態的,forward_only)。刪除這些似乎使我們在 SEND CONVERSATION 上看到的鎖在本質上更加短暫(或者至少我們看到的時間要低得多)。
  • 我們基本上並排執行了兩個解決方案(Service Broker 解決方案後端(用於在生產負載下進行測試))和目前解決方案(跨越許多表的可怕查詢)。

作為附帶的好處,這發現了一個 Ghost Record Cleanup 問題,雖然它不在 Service Broker 表(系統或隊列)上,但它在我們的系統中非常猖獗,並且症狀與我們的“沒有明確的原因”非常吻合我們有時會遇到的問題。對此的調查正在進行中,我們正試圖找到對其有貢獻的表,我們可能會定期重建它們的索引。

再一次感謝你。

*** 2021 年更新 ***

我對此再次投了贊成票,所以我想回來重新審視。在我提出這個問題後不久,我們最終放棄了 Service Broker,因為我們的事務工作量仍然太高/太快而無法有效工作。我們最終為我們的高吞吐量消息系統遷移到了這種隊列樣式,並且效果很好。

http://kejser.org/implementing-message-queues-in-relational-databases/

引用自:https://dba.stackexchange.com/questions/187571