使用 Microsoft.Data.SqlClient 的 SQL Server 連線共用

Microsoft.Data.SqlClient 連線集區會重複使用經過驗證的實體連線。 SqlConnection.OpenOpenAsync 會檢查連線池中是否有可用的連線。 CloseDisposeDisposeAsync 會將其重設並傳回。 此方法避免每次操作都需進行網路連線、認證及會話設定。

Pooling 預設為啟用狀態。 請使用此應用模式:

await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);

using var command = new SqlCommand(sql, connection);
await command.ExecuteNonQueryAsync(cancellationToken);

晚開門、早處理,讓池子管理實體連接。 不要讓單一SqlConnection項目全域開放。

了解池金鑰

連線只能從與其相符的集區中被重複使用。 集區金鑰不只包含目的地伺服器。

Input 池塘行為
連接字串 文字必須完全一致。 關鍵字順序的差異會產生獨立的池,即使有效設定相同。
Windows 整合式驗證 Windows 身份是金鑰的一部分。 相同字串在不同識別身分下會建立不同的集區。
SqlCredential 物件實例是金鑰的一部分。 即使包含相同的使用者名稱和密碼,獨立的實例也會建立獨立的集區。
SqlConnection.AccessToken 存取權杖值是金鑰的一部分。 替換代幣字串可能會建立新的集區,並使現有集區中的連線仍以舊代幣通過驗證。
SqlConnection.AccessTokenCallback 回呼是關鍵的一部分。 重複使用同一個回調實例,讓應該共用一個池的連線。 回傳的代幣值不是池金鑰。
自訂 SSPI 情境提供者 提供者實例參與連線設定。 對於應共用同一連線集區的連線,請重複使用同一個提供者執行個體。
環境交易 已登錄的連線在對應的集區內使用交易專屬的子分區。

資料庫、驗證模式、加密選項、應用程式名稱、集區選項,以及其他所有連接字串值,都是透過完全相符的字串內容來發揮作用。

建立一個典型的 連接字串 並重複使用。 避免以 Application NameWorkstation ID或其他關鍵字標示每個請求值。

選擇能夠池化的憑證 API

對於 Microsoft Entra ID 存取權杖,請使用 Microsoft.Data.SqlClient 提供的驗證模式或穩定版的 AccessTokenCallback

AccessTokenCallback 已於 Microsoft.Data.SqlClient 5.2 中引入。 驅動程式在需要權杖時會呼叫它,並可為重複使用的集區請求更新後的權杖。 保留驅動程式提供的認證參數的確定回調,並重複使用同一個代理實例。

當程式碼直接設定 AccessToken 時:

  • 標記字串成為池金鑰的一部分。
  • 應用程式自行負責權杖的到期與更新。
  • 一個池化的實體連線可能會比用來建立它的代幣還長。
  • 如果該代幣池無法安全使用,則在替換過期的代幣後再打電話 ClearPool

不要為每個要求建立新的 lambda 回呼函式或憑證物件。 物件身份差異可能會使池子分裂。

Microsoft.Data.SqlClient 7.0 新增了用於自訂 Kerberos 或 NTLM 協商的 SspiContextProvider。 將提供程序視為應用程式層級的連線設定,而非個別請求的狀態。

每個池的規模

這些連線字串選項控制同一個連線集區:

Keyword 預設 Effect
Pooling true 啟用或停用池化。
Min Pool Size 0 設定池建立後保留的最少實體連線數。
Max Pool Size 100 設定池中物理連線的最大數量。
Connect Timeout 15 秒 設定在沒有可用的連線時,Open 會等待多久。
Load Balance Timeout 0 當連線回到池時,若其年齡超過設定值,則會丟棄該連線。 Connection Lifetime 是個化名。

隨著需求增加,池子會產生連結,直到達到 Max Pool Size。 當所有連線都已使用時,稍後開啟等待連線返回。 若等待時間超過 Connect Timeout,開啟失敗。

檢查前不要加注 Max Pool Size

  • 每條路徑上都配置了每個連線和讀取器。
  • 指令和交易都能迅速完成。
  • 查詢工作負載未遭到阻塞或飽和。
  • 資料庫連線上限可支援 Max Pool Size 乘以每個應用程式執行個體中的每個連線池。

Min Pool Size 值在閒置期間保持連線暢通。 僅在量測結果顯示有必要使用暖連線時才使用。 它通常對抗可擴展至零、無伺服器自動暫停和可爆發的雲端設計。

在預設為 Load Balance Timeout=0 的情況下,定期清理通常會在約四到八分鐘後移除高於 Min Pool Size 的未使用連線;或者,當連線集區偵測到與伺服器的連線已中斷時,也會將其移除。 請將該時間間隔視為實作上的行為,而非每條連線各自的閒置保證。 連線池不會在每次取出連線前都傳送驗證查詢,因為這樣一次往返會抵消連線池的大部分效益。

處理認證封鎖期間

在認證逾時或其他認證失敗後,池子可能會進入封鎖期。 在此期間,匹配的開放嘗試會重新拋出原始例外,而無需再嘗試驗證。

第一個封鎖期間為五秒。 又一次失敗後,這段時間會加倍到一分鐘。

Pool Blocking Period 控制此行為:

價值觀 行為
Auto 啟用一般 SQL Server 端點的阻擋,並對已識別的 Azure SQL 端點後綴關閉阻擋。 Vanity DNS 名稱可能不會接收 Azure 的行為。
AlwaysBlock 啟用每個端點的封鎖期間。
NeverBlock 關閉封鎖期。

除非應用程式的重試設計需要不同的選擇,否則就保留 Auto 。 停用封鎖時段可能會將認證資料、防火牆或服務中斷問題演變成驗證風暴。

封鎖期間和可設定的重試邏輯是分開的。 在封鎖期間開啟同一池的重試提供者會接收快取的例外。

管理連線存留期與清除

當池子識別到致命錯誤(如故障轉移)時,會自動清除受影響的池子。 池會關閉閒置的連接,並在回來時丟棄已停用的連接。

針對已知的設定或認證界線,使用清除 API:

  • ClearPool 清除與一個 SqlConnection 配置相關聯的集區。
  • ClearAllPools清除處理序或應用程式定義域中的每個 Microsoft.Data.SqlClient 集區。

池子會關閉清空池中的閒置連接。 池會標記目前正在使用的連線,因此在還回時會丟棄它們。

清空池會讓後續開啟的玩家進行實體登入。 不要把它當作定期維護、一般錯誤處理工具,或是處理連線的替代品。

Load Balance Timeout 提供依年齡漸進的人員流動。 當部署或叢集服務需要讓舊有的實體連線隨著時間逐步淘汰時,請使用它。 確認所選值不會造成過度的硬連接。

了解交易

使用 Enlist=true(預設值)時,在 System.Transactions.Transaction.Current 內開啟的連線會自動登錄至該交易。

當已加入交易的連線關閉後,連線集區會將其放入該交易專屬的子區段。 同一交易下後續開啟的可重複使用。 實體連線要等到交易完成後,才會返回通用連線池。

因此,持續時間過長或已遭捨棄的環境交易可能:

  • 請勿將實體連線納入一般集區。
  • 在邏輯連線關閉後占用連線池容量。
  • 使伺服器鎖和交易狀態維持作用中。

將交易控制在明確範圍內,明確地完成交易,並監控停滯連線。 僅在連線必須保持在環境交易之外時才會設定 Enlist=false

防止池碎片化

池碎片化會產生許多小型池,而非少數可重複使用的池。 常見的原因包括:

  • 連線字串關鍵字順序或別名差異。
  • 每個客戶、使用者、請求或資料庫各有一個連線字串。
  • 在多種 Windows 身份下整合認證。
  • 新增 SqlCredential、存取權杖回調,或每個請求的 SSPI 提供者實例。
  • 每次刷新都會更換的直接存取權杖。
  • 高基數應用程式名稱或工作站 ID。

將連線字串 SqlConnectionStringBuilder 正規化並集中建立連線。

若應用程式有意連接多個資料庫或身份,應將所得的池數納入容量規劃中。 不要使用不受信任的資料庫名稱來執行 USE,以免導致集區崩潰。 資料庫隔離、權限、會話狀態及池重置行為必須明確。

將應用程式角色和工作階段狀態納入考量

池會重置可重用的 SQL Server 會話狀態,然後再將實體連線指派給另一個邏輯連線。 應用程式程式碼仍應在其工作單元內設定所需的會話狀態。

使用 sp_setapprole 啟用的 SQL Server 應用程式角色,無法安全地重設以供一般連線集區使用。 建議使用資料庫使用者、內含使用者、角色、資料列層級安全性或其他授權設計。 若應用程式角色無法避免,請使用文件化的 Cookie 反轉模式,或在測試後停用該孤立路徑的池化。

丟棄讀取器、結束或回滾交易,且連線關閉時不要讓指令持續執行。 不要依賴臨時資料表或其他會話狀態能在邏輯連線間存活。

使用雲端代管的集區模式

對於 Azure 應用程式服務、Azure Functions、容器、Kubernetes 及其他水平擴充的主機:

  • 計算所有實例、程序、池鍵及副本間可能的資料庫連線。
  • 請使用受控識別或穩定的存取權杖回呼函式,而不要在連線物件中輪替權杖字串。
  • 除非經量測的冷啟動需求足以證明必須保留工作階段,否則請保持 Min Pool Size=0
  • 預期新實例會從空池開始。
  • 在服務相同工作負載的實例間,保持連線字串保持一致。
  • 限制連線嘗試次數與重試次數,以避免在故障切換或橫向擴充期間發生同步登入尖峰。
  • 為 Azure SQL 與其他受支援的多重位址 TCP 端點設定 MultiSubnetFailover=true

連線池是應用程式程序本機端專屬的。 它們不會在應用程式實例、容器或主機間共享。

診斷集區運作情形

使用 SqlClient 診斷計數器 來觀察:

  • 硬連接與斷開,代表實體伺服器連線。
  • 軟連接與斷開,代表池子的檢查與返回。
  • 使用中和閒置的集區連線。
  • 活躍的泳池團體與泳池。
  • 靜止連結。
  • 重新回收的連線,應用程式程式碼沒有丟棄邏輯連線。

將用戶端計數器與 SQL Server 會話、等待、阻擋及資源限制相關聯。 池逾時可能代表連線洩漏、查詢緩慢、交易阻塞、過多並發、池碎片化或資料庫容量限制。

使用 事件來源追蹤 來取得針對 pooler 的追蹤記錄。 追蹤很冗長。 啟用有界診斷視窗,並保護所有擷取的連線元資料。

生產檢查清單

  • 讓集區化保持啟用。
  • 每個工作負載和資料庫都重複使用同一個標準連線字串。
  • 在每條路徑上丟棄連線、指令、讀取器和交易。
  • 重用憑證、權杖回調及 SSPI 提供者實例。
  • 設定有限連線和指令逾時。
  • 為所有應用程式執行個體規劃整體連線預算。
  • 監控硬連接數、連線池數量、可用連線、停滯和逾時。
  • 只有當提供者無法偵測到憑證、令牌或設定邊界,或診斷確認連線仍過時時,才清除池。
  • 在正式上線前,先對擴展能力、故障轉移及憑證重新整理行為進行負載測試。