診斷 Azure Cosmos DB .NET SDK 中的緩慢要求並進行疑難排解
適用於:NoSQL
在 Azure Cosmos DB 中,您可能會注意到緩慢要求。 延遲可能有各種原因,例如要求節流或應用程式的設計方式。 本文說明此問題的各種根本原因。
要求率太大
要求節流是緩慢要求最常見的原因。 如果要求超過資料庫或容器配置的要求單位,Azure Cosmos DB 會將要求節流。 SDK 有內建的邏輯可重試這些要求。 要求率太大的疑難排解文章說明如何檢查要求是否受到節流。 本文也會討論如何調整您的帳戶,以避免未來發生這些問題。
應用程式設計
當您設計應用程式時,請遵循 .NET SDK 最佳做法以獲得最佳效能。 如果您的應用程式未遵循 SDK 最佳做法,您可能會遇到緩慢或失敗的要求。
開發應用程式時,請考慮下列事項:
- 應用程式與 Azure Cosmos DB 帳戶應該位於相同的區域。
- 您的 ApplicationRegion 或 ApplicationPreferredRegions 應該反映您的區域喜好設定,並指向應用程式部署所在的區域。
- 網路介面可能會因為高流量而有瓶頸。 如果應用程式是在 Azure 虛擬機器上執行,則有可行的因應措施:
- 請考慮使用已啟用加速網路的虛擬機器。
- 啟用現有虛擬機器上的加速網路。
- 請考慮使用較高的終端虛擬機器。
- 偏好直接連線模式。
- 避免 CPU 使用量過高。 請務必查看最大 CPU 使用量,而非多數記錄系統預設的平均。 只要高於大約 40% 就可能增加延遲。
中繼資料作業
如果您需要確認資料庫或容器存在,請勿在執行項目作業之前透過呼叫 Create...IfNotExistsAsync
或 Read...Async
來進行。 只有在應用程式啟動且有必要時才應進行驗證 (例如您預期應用程式將會刪除)。 這些中繼資料作業會產生額外的延遲、沒有服務等級協定 (SLA),而且有其自己的個別限制。 這些作業不會像資料作業一樣進行調整。
大量模式上的緩慢要求
大量模式是輸送量最佳化模式,適用於大量資料作業,而非延遲最佳化模式;而其目的在於使可用的輸送量飽和。 如果您在使用大量模式時遇到緩慢的要求,請確定:
- 您的應用程式在發行設定中進行編譯。
- 偵錯應用程式時並未測量延遲 (未附加任何偵錯工具)。
- 作業量偏高,針對少於 1000 個的作業請勿使用大量模式。 您佈建的輸送量會決定每秒可以處理的作業數目,大量模式的目標在於盡可能利用輸送量。
- 監視容器是否有節流案例。 如果容器受到大量節流,表示資料量大於您佈建的輸送量,而您需要擴大容器或減少資料量 (可以一次建立較小批次的資料)。
- 您已正確使用
async/await
模式來處理所有並行工作,而且未封鎖任何非同步作業。
擷取診斷
SDK 中的所有回應 (包括 CosmosException
) 都具有 Diagnostics
屬性。 此屬性記錄與單一要求相關的所有資訊,包括是否有重試或任何暫時性失敗。
診斷以字串形式傳回。 每個版本會改進以針對不同情節進行疑難排解,所以此字串也隨之變更。 在每一版的 SDK 中,此字串的格式都有重大變更。 請勿剖析此字串,以免造成重大變更。 下列程式碼範例示範如何透過使用 .NET SDK 來讀取診斷記錄:
try
{
ItemResponse<Book> response = await this.Container.CreateItemAsync<Book>(item: testItem);
if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan)
{
// Log the response.Diagnostics.ToString() and add any additional info necessary to correlate to other logs
}
}
catch (CosmosException cosmosException)
{
// Log the full exception including the stack trace with: cosmosException.ToString()
// The Diagnostics can be logged separately if required with: cosmosException.Diagnostics.ToString()
}
// When using Stream APIs
ResponseMessage response = await this.Container.CreateItemStreamAsync(partitionKey, stream);
if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan || !response.IsSuccessStatusCode)
{
// Log the diagnostics and add any additional info necessary to correlate to other logs with: response.Diagnostics.ToString()
}
3.19 版和更新版本中的診斷
JSON 結構隨著每一版的 SDK 而有重大變更。 所以剖析並不安全。 JSON 代表由 SDK 所處理要求的樹狀結構。 下列各節涵蓋一些需要探討的重要事項。
CPU 歷程記錄
高 CPU 使用率是緩較要求最常見的原因。 為了達到最佳延遲,CPU 使用率應保持在約 40% 之間。 請使用 10 秒的間隔來監視最大 (非平均) CPU 使用率。 跨分割區查詢較常出現 CPU 尖峰,其中,要求可能在單一查詢中建立多個連線。
逾時包括診斷,其中包含下列項目,例如:
"systemHistory": [
{
"dateUtc": "2021-11-17T23:38:28.3115496Z",
"cpu": 16.731,
"memory": 9024120.000,
"threadInfo": {
"isThreadStarving": "False",
....
}
},
{
"dateUtc": "2021-11-17T23:38:38.3115496Z",
"cpu": 16.731,
"memory": 9024120.000,
"threadInfo": {
"isThreadStarving": "False",
....
}
},
...
]
- 如果
cpu
值超過 70%,則逾時可能起因於 CPU 耗盡。 在此情況下,解決方案是調查高 CPU 使用率的來源並將其降低,或將電腦調整為較大的資源大小。 - 如果
threadInfo/isThreadStarving
節點有True
值,則原因是執行緒耗盡。 在此情況下,解決方案是調查執行緒耗盡的一或多個來源 (可能已鎖定的執行緒),或將一或多台電腦調整為較大的資源大小。 - 如果量測之間的
dateUtc
時間不是 10 秒左右,則也指出爭用執行緒集區。 CPU 會測量為每 10 秒在執行緒集區中加入佇列的獨立工作。 如果度量之間的時間較長,表示非同步工作無法及時處理。 最常見的案例是您的應用程式程式碼封鎖透過非同步程式碼的呼叫。
解決方案
應該擴大或擴增使用 SDK 的用戶端應用程式。
HttpResponseStats
HttpResponseStats
是移至 閘道的要求。 即使在直接模式下,SDK 也會從閘道取得所有中繼資料資訊。
如果要求速度緩慢,請先確認上述任何建議皆未產生所需的結果。 如果仍然緩慢,則不同的模式指出不同的問題。 下表提供更多詳細資料。
要求數目 | 案例 | 描述 |
---|---|---|
單一對全部 | 要求逾時或 HttpRequestExceptions |
指出 SNAT 連接埠耗盡,或電腦上資源不足,無法及時處理要求。 |
一位數或很小的百分比 (不違反 SLA) | 全部 | 一位數或很小百分比的緩慢要求,即可能起因於多個不同的暫時性問題,這應該在意料之中。 |
全部 | 全部 | 指出基礎結構或網路有問題。 |
違反 SLA | 未捨棄對應用程式和 SLA 的變更。 | 指出 Azure Cosmos DB 服務有問題。 |
"HttpResponseStats": [
{
"StartTimeUTC": "2021-06-15T13:53:09.7961124Z",
"EndTimeUTC": "2021-06-15T13:53:09.7961127Z",
"RequestUri": "https://127.0.0.1:8081/dbs/347a8e44-a550-493e-88ee-29a19c070ecc/colls/4f72e752-fa91-455a-82c1-bf253a5a3c4e",
"ResourceType": "Collection",
"HttpMethod": "GET",
"ActivityId": "e16e98ec-f2e3-430c-b9e9-7d99e58a4f72",
"StatusCode": "OK"
}
]
StoreResult
StoreResult
代表使用直接模式搭配 TCP 通訊協定對 Azure Cosmos DB 提出的單一要求。
如果仍然緩慢,則不同的模式指出不同的問題。 下表提供更多詳細資料。
要求數目 | 案例 | 描述 |
---|---|---|
單一對全部 | StoreResult 包含 TransportException |
指出 SNAT 連接埠耗盡,或電腦上資源不足,無法及時處理要求。 |
一位數或很小的百分比 (不違反 SLA) | 全部 | 一位數或很小百分比的緩慢要求,即可能起因於多個不同的暫時性問題,這應該在意料之中。 |
全部 | 全部 | 基礎結構或網路有問題。 |
違反 SLA | 要求包含多個失敗錯誤碼,例如 410 |
指出 Azure Cosmos DB 服務或用戶端機器發生問題。 |
違反 SLA | StorePhysicalAddress 相同,沒有失敗狀態碼。 |
Azure Cosmos DB 可能發生問題。 |
違反 SLA | StorePhysicalAddress 有相同的分割區識別碼,但複本識別碼不同,沒有失敗狀態碼。 |
Azure Cosmos DB 可能發生問題。 |
違反 SLA | StorePhysicalAddress 為隨機,沒有失敗狀態碼。 |
指向電腦的問題。 |
對於單一要求的多個存放區結果,請注意下列事項:
- 強式一致性和限定過期一致性永遠都至少有兩個儲存結果。
- 檢查每個
StoreResult
中的狀態碼。 發生多個不同的暫時性失敗時,SDK 會自動重試。 SDK 會持續改進以涵蓋更多情況。
RequestTimeline
顯示在傳輸層中傳送和接收要求時各階段所花的時間。
ChannelAcquisitionStarted
:取得或建立新連線的時間。 您可以基於許多原因來建立連線,例如:先前的連線因閒置而使用 CosmosClientOptions.IdleTcpConnectionTimeout 予以關閉、並行要求數量超過 CosmosClientOptions.MaxRequestsPerTcpConnection、連線因網路錯誤而予以關閉,或應用程式未遵循 Singleton 模式,而且會持續建立新的執行個體。 連線在建立之後會重複用於後續要求,因此除非發生先前提到的問題,否則這應該不會影響 P99 延遲。Pipelined
:將要求寫入 TCP 通訊端所花費的時間。 一次只能在 TCP 通訊端上寫入一個要求,較大的值表示 TCP 通訊端上存在瓶頸,這通常與應用程式程式碼或較大要求大小導致的鎖定執行緒有關。Transit time
:在 TCP 通訊端上寫入要求後在網路上花費的時間。 將此數字與BELatencyInMs
相比較。 如果BELatencyInMs
很小,表示時間都耗費在網路上,而非 Azure Cosmos DB 服務。 如果要求因超時而失敗,則表示用戶端在沒有回應的情況下等待了多長時間,來源是網路延遲。Received
:SDK 收到回應和處理回應之間的時間。 較大的值通常是由執行緒耗盡或鎖定執行緒引起的。
ServiceEndpointStatistics
特定後端伺服器的相關資訊。 SDK 可以根據擱置的要求數目和 MaxConcurrentRequestsPerConnection 來開啟單一後端伺服器的多個連線。
inflightRequests
後端伺服器的擱置要求數目 (可能來自不同的分割區)。 大量數目可能會導致更多流量和較高的延遲。openConnections
是開啟單一後端伺服器的連線總數目。 如果這個數目很高,這很適合用於顯示 SNAT 連接埠耗盡。
ConnectionStatistics
要求受指派的特定連線 (新或舊連線) 相關資訊。
waitforConnectionInit
:目前的要求正在等候新的連線初始化完成。 這將導致較高的延遲。callsPendingReceive
:傳送此呼叫之前擱置接收的呼叫數目。 大量數目可以顯示此呼叫之前有許多呼叫,而且可能會導致較高的延遲。 如果此數目很高,則會指向可能造成封鎖問題的標頭行,原因是查詢或摘要作業等其他要求需要很長的時間來處理。 請嘗試降低 CosmosClientOptions.MaxRequestsPerTcpConnection 以增加通道數目。LastSentTime
:傳送至此伺服器的上次要求時間。 您可以同時用此項目與 LastReceivedTime 來查看連線或端點問題。 例如,如果有許多接收逾時,「傳送」時間會比「接收」時間長很多。lastReceive
:從此伺服器接收的上次要求時間lastSendAttempt
:上次傳送嘗試的時間
要求和回應大小
requestSizeInBytes
:傳送至 Azure Cosmos DB 的要求大小總計responseMetadataSizeInBytes
:從 Azure Cosmos DB 傳回的標頭大小responseBodySizeInBytes
:從 Azure Cosmos DB 傳回的內容大小
"StoreResult": {
"ActivityId": "bab6ade1-b8de-407f-b89d-fa2138a91284",
"StatusCode": "Ok",
"SubStatusCode": "Unknown",
"LSN": 453362,
"PartitionKeyRangeId": "1",
"GlobalCommittedLSN": 0,
"ItemLSN": 453358,
"UsingLocalLSN": true,
"QuorumAckedLSN": -1,
"SessionToken": "-1#453362",
"CurrentWriteQuorum": -1,
"CurrentReplicaSetSize": -1,
"NumberOfReadRegions": 0,
"IsValid": true,
"StorePhysicalAddress": "rntbd://127.0.0.1:10253/apps/DocDbApp/services/DocDbServer92/partitions/a4cb49a8-38c8-11e6-8106-8cdcd42c33be/replicas/1s/",
"RequestCharge": 1,
"RetryAfterInMs": null,
"BELatencyInMs": "0.304",
"transportRequestTimeline": {
"requestTimeline": [
{
"event": "Created",
"startTimeUtc": "2022-05-25T12:03:36.3081190Z",
"durationInMs": 0.0024
},
{
"event": "ChannelAcquisitionStarted",
"startTimeUtc": "2022-05-25T12:03:36.3081214Z",
"durationInMs": 0.0132
},
{
"event": "Pipelined",
"startTimeUtc": "2022-05-25T12:03:36.3081346Z",
"durationInMs": 0.0865
},
{
"event": "Transit Time",
"startTimeUtc": "2022-05-25T12:03:36.3082211Z",
"durationInMs": 1.3324
},
{
"event": "Received",
"startTimeUtc": "2022-05-25T12:03:36.3095535Z",
"durationInMs": 12.6128
},
{
"event": "Completed",
"startTimeUtc": "2022-05-25T12:03:36.8621663Z",
"durationInMs": 0
}
],
"serviceEndpointStats": {
"inflightRequests": 1,
"openConnections": 1
},
"connectionStats": {
"waitforConnectionInit": "False",
"callsPendingReceive": 0,
"lastSendAttempt": "2022-05-25T12:03:34.0222760Z",
"lastSend": "2022-05-25T12:03:34.0223280Z",
"lastReceive": "2022-05-25T12:03:34.0257728Z"
},
"requestSizeInBytes": 447,
"responseMetadataSizeInBytes": 438,
"responseBodySizeInBytes": 604
},
"TransportException": null
}
失敗率違反 Azure Cosmos DB SLA
連絡 Azure 支援。