共用方式為


診斷 Azure Cosmos DB .NET SDK 中的緩慢要求並進行疑難排解

適用於:NoSQL

在 Azure Cosmos DB 中,您可能會注意到緩慢要求。 延遲可能有各種原因,例如要求節流或應用程式的設計方式。 本文說明此問題的各種根本原因。

要求率太大

要求節流是緩慢要求最常見的原因。 如果要求超過資料庫或容器配置的要求單位,Azure Cosmos DB 會將要求節流。 SDK 有內建的邏輯可重試這些要求。 要求率太大的疑難排解文章說明如何檢查要求是否受到節流。 本文也會討論如何調整您的帳戶,以避免未來發生這些問題。

應用程式設計

當您設計應用程式時,請遵循 .NET SDK 最佳做法以獲得最佳效能。 如果您的應用程式未遵循 SDK 最佳做法,您可能會遇到緩慢或失敗的要求。

開發應用程式時,請考慮下列事項:

中繼資料作業

如果您需要確認資料庫或容器存在,請勿在執行項目作業之前透過呼叫 Create...IfNotExistsAsyncRead...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 支援

下一步