Azure Cosmos DB 和 .NET 的效能秘訣

適用於:NoSQL

Azure Cosmos DB 是一個既快速又彈性的分散式資料庫,可在獲得延遲程度與輸送量保證的情況下順暢地調整。 使用 Azure Cosmos DB 時,您不必進行主要的架構變更,或是撰寫複雜的程式碼來調整您的資料庫。 相應增加和減少就像進行單一 API 呼叫一樣簡單。 若要深入了解,請參閱佈建容器輸送量佈建資料庫輸送量

由於 Azure Cosmos DB 是透過網路呼叫存取,所以您可以在使用 SQL .NET SDK 時進行用戶端最佳化,以達到最高效能。

若您想要改善資料庫效能,請考慮下列各節所提供的選項。

裝載建議

開啟伺服器端記憶體回收

在部份情況下,降低記憶體回收頻率可能會有幫助。 在 .NET 中,請將 gcServer 設為 true

擴增用戶端工作負載

若您是以高輸送量層級進行測試,或是以大於 50,000 每秒要求單位 (RU/s) 的速率進行測試,用戶端應用程式可能會變成工作負載的瓶頸。 這是因為電腦的 CPU 或網路的使用率可能會達到上限。 如果到了這一刻,您可以將用戶端應用程式向外延展至多部伺服器,以繼續將 Azure Cosmos DB 帳戶再往前推進一步。

注意

高 CPU 使用方式可能會導致延遲增加和要求逾時例外狀況。

中繼資料作業

請勿透過在最忙碌的路徑中呼叫 Create...IfNotExistsAsync 和/或 Read...Async,和/或在執行項目作業之前,確認資料庫和/或容器是否存在。 只有在應用程式啟動且有必要時才應進行驗證 (例如您預期應用程式將會刪除,否則沒有必要)。 這些中繼資料作業會產生額外的端對端延遲,也沒有 SLA,且因為各自的限制而不像資料作業一樣會縮放。

記錄和追蹤

部份環境已啟用 .NET DefaultTraceListener。 DefaultTraceListener 會在生產環境中造成效能問題,導致高 CPU 和 I/O 瓶頸。 請將應用程式從生產環境的 TraceListeners 中移除,藉此檢查並確定您的應用程式已停用 DefaultTraceListener。

最新 SDK 版本 (3.23.0 以上) 偵測到 DefaultTraceListener 時會自動將其移除,而針對較舊的版本,您可以透過下列方式移除:

if (!Debugger.IsAttached)
{
    Type defaultTrace = Type.GetType("Microsoft.Azure.Cosmos.Core.Trace.DefaultTrace,Microsoft.Azure.Cosmos.Direct");
    TraceSource traceSource = (TraceSource)defaultTrace.GetProperty("TraceSource").GetValue(null);
    traceSource.Listeners.Remove("Default");
    // Add your own trace listeners
}

網路

原則︰使用直接連接模式

.NET V3 SDK 的預設連線模式是直接透過 TCP 通訊協定進行連線。 當您在 CosmosClientOptions 中建立 CosmosClient 執行個體時,可以設定連線模式。 若要深入了解不同的連線選項,請參閱連線模式一文。

string connectionString = "<your-account-connection-string>";
CosmosClient client = new CosmosClient(connectionString,
new CosmosClientOptions
{
    ConnectionMode = ConnectionMode.Gateway // ConnectionMode.Direct is the default
});

暫時連接埠耗盡

如果您的執行個體呈現高連線量或高連接埠使用量,請先確認您的用戶端執行個體為單一資料庫。 換句話說,用戶端執行個體在應用程式的存留期內應該是唯一的。

當用戶端透過 TCP 通訊協定執行時,會利用長時間執行的連線,將延遲縮到最短。 這與 HTTPS 通訊協定相反,只要處於非使用狀態下兩分鐘,HTTPS 通訊協定就會終止連線。

在有稀疏存取的情況下,如果您發現相較於網路閘道模式存取,連線計數更高,此時可以:

  • CosmosClientOptions.PortReuseMode 屬性設定為 PrivatePortPool (只對架構版本 4.6.1 版和更新版本,以及 .NET Core 2.0 版和更新版本有效)。 這個屬性可讓 SDK 針對各種 Azure Cosmos DB 目的地端點,使用較小的暫時連接埠集區。
  • CosmosClientOptions.IdleTcpConnectionTimeout 屬性設定為大於或等於 10 分鐘。 建議的值為 20 分鐘到 24 小時。

為了效能,請將用戶端共置在相同的 Azure 區域中

可能的話,請將任何呼叫 Azure Cosmos DB 的應用程式放在與 Azure Cosmos DB 資料庫相同的區域中。 以下是約略的比較:在相同區域內對 Azure Cosmos DB 進行的呼叫會在 1-2 毫秒 (ms) 內完成,但美國西岸和美國東岸之間的延遲則會大於 50 毫秒。 視要求所採用的路由而定,各項要求從用戶端傳遞至 Azure 資料中心界限的這類延遲可能會有所不同。

請確保呼叫端應用程式與佈建的 Azure Cosmos DB 端點位於相同的 Azure 區域中,如此一來便有可能達到最低的延遲。 如需可用區域的清單,請參閱 Azure 區域

在相同區域中共置用戶端。

增加執行緒/工作數目

由於對 Azure Cosmos DB 的呼叫要透過網路進行,因此您可能需要改變要求的並行處理原則程度,以便讓用戶端應用程式在不同要求之間的等待時間降到最低。 例如,如果您使用的是 .NET 工作平行程式庫,請依照從 Azure Cosmos DB 讀取或寫入的數百個工作的順序來建立。

啟用加速網路以降低延遲和 CPU 抖動

建議您遵循指示,以在 Windows (按一下以取得指示)Linux (按一下以取得指示) Azure VM 中啟用加速網路,以求達到最大效能。

如果沒有加速網路,在 Azure VM 和其他 Azure 資源之間傳輸的 IO,可能反而會透過位於 VM 和其網路卡之間的主機和虛擬交換器來路由傳送。 將主機和虛擬交換器內嵌在資料路徑中,不僅會增加通道的延遲和抖動,還會佔用 VM 的 CPU 週期。 使用加速網路時,VM 會直接使用不含中繼的 NIC;由主機和虛擬交換器處理的任何網路原則詳細資料,都會在 NIC 的硬體中加以處理;完全略過主機和虛擬交換器。 一般來說可以預期降低延遲並提高輸送量,而且啟用加速網路時,延遲情形會更為一致,CPU 使用率也會降低。

限制:VM OS 必須支援加速網路,而且只有在 VM 停止並解除配置時,才能啟用加速網路。 無法使用 Azure Resource Manager 部署 VM。 App Service 未啟用加速網路。

如需詳細資訊,請參閱 WindowsLinux 指示。

SDK 使用方式

安裝最新的 SDK

Azure Cosmos DB SDK 會持續改善以提供最佳效能。 若要判斷最新的 SDK 並檢閱改善項目,請參閱 Azure Cosmos DB SDK 頁面。

使用串流 API

.NET SDK V3 包含可在不序列化的情況下接收和傳回資料的串流 API。

不會直接從 SDK 取用回應,而會將回應轉送至應用程式層的中間層應用程式,可從串流 API 受益。 如需串流處理的範例,請參閱項目管理範例。

在應用程式存留期內使用單一 Azure Cosmos DB 用戶端

每個 CosmosClient 執行個體都是安全執行緒,並且在直接模式中運作時執行有效率的連線管理和位址快取。 若要允許有效率的連線管理和更恰當的 SDK 用戶端效能,建議您在應用程式的存留期內,針對與應用程式互動的每個帳戶,根據 AppDomain 來使用單一執行個體。

如需處理多個帳戶的多租使用者應用程式,請參閱 相關的最佳做法

當您在 Azure Functions 上工作時,執行個體也應遵循現有的指導方針並各自獨立。

避免封鎖呼叫

Azure Cosmos DB SDK 應能夠同時處理許多要求。 非同步 API 允許小型執行緒集區透過不等候封鎖呼叫來處理數千個並行要求。 執行緒可以處理另一個要求,而不是等候長時間執行的同步工作完成。

使用 Azure Cosmos DB SDK 的應用程式常出現的效能問題,就是封鎖可能為非同步的呼叫。 許多同步封鎖呼叫會導致執行緒集區耗盡和回應時間降級。

請勿

  • 呼叫 Task.WaitTask.Result 來封鎖非同步執行。
  • 使用 Task.Run 將同步 API 改為非同步。
  • 透過通用程式碼路徑取得鎖定。 Azure Cosmos DB .NET SDK 的架構為平行執行程式碼時效能最佳。
  • 呼叫 Task.Run 並隨即等待。 ASP.NET Core 已在一般執行緒集區執行緒上執行應用程式程式碼,因此呼叫 Task.Run 只會導致額外且不必要的執行緒集區排程。 即使已排程的程式碼會封鎖執行緒,Task.Run 還是無法防止這種情況。
  • 請勿將 ToList() 用於 Container.GetItemLinqQueryable<T>(),因為它會使用封鎖呼叫同步清空查詢。 請使用 ToFeedIterator() 以非同步方式清空查詢。

建議:

  • 以非同步方式呼叫 Azure Cosmos DB .NET API。
  • 整個呼叫堆疊屬於非同步,可受益於非同步/等候模式。

分析工具如 PerfView,可用來尋找經常新增至執行緒集區的執行緒。 Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start 事件表示已新增至執行緒集區的執行緒。

停用寫入作業的內容回應

對於具有大量建立承載的工作負載,請將 EnableContentResponseOnWrite 要求選項設定為 false。 服務就不會再將已建立或已更新的資源傳回至 SDK。 一般來說,因為應用程式具有正在建立的物件,所以不需要服務來傳回物件。 標頭值仍可存取,例如要求費用。 停用內容回應有助於改善效能,因為 SDK 不再需要配置記憶體或序列化回應主體。 這也可減少網路頻寬使用量,進一步提升效能。

ItemRequestOptions requestOptions = new ItemRequestOptions() { EnableContentResponseOnWrite = false };
ItemResponse<Book> itemResponse = await this.container.CreateItemAsync<Book>(book, new PartitionKey(book.pk), requestOptions);
// Resource will be null
itemResponse.Resource

啟用大量功能,將輸送量而非延遲最佳化

在需要大量輸送而延遲無關緊要的情況下,可啟用大量功能。 如需如何啟用大量功能以及該用於哪些情況下的詳細資訊,請參閱大量支援的簡介

使用網路閘道模式時增加每部主機的 System.Net MaxConnections

當您使用網路閘道模式,系統會透過 HTTPS/REST 發出 Azure Cosmos DB 要求。 這些要求受限於每個主機名稱或 IP 位址的預設連線限制。 您可能需要將 MaxConnections 設為較高的值 (100 至 1000),這樣一來用戶端程式庫就可以使用多個同時連至 Azure Cosmos DB 的連線。 在 .NET SDK 1.8.0 和更新版本中,ServicePointManager.DefaultConnectionLimit 的預設值是 50。 若要變更此值,您可以將 Documents.Client.ConnectionPolicy.MaxConnectionLimit 設定為較高的值。

增加執行緒/工作數目

請參閱本文中「網路」一節中的增加執行緒/工作數目

查詢作業

如需查詢作業,請參閱查詢的效能秘訣

編製索引原則

將未使用的路徑排除於索引編製外以加快寫入速度

Azure Cosmos DB 的編製索引原則也可讓您運用索引路徑 (IndexingPolicy.IncludedPaths and IndexingPolicy.ExcludedPaths),指定要在編製索引中包含或排除的文件路徑。

只為所需的路徑編制索引,有助於改善寫入效能、減少寫入作業的 RU 費用,以及在事先已知查詢模式的情況下,減少索引儲存體。 這是因為編製索引的成本與編製索引的唯一路徑數目直接相互關聯。 例如,下列程式碼示範如何使用 "*" 萬用字元,將文件 (也稱為樹狀子目錄) 的整個區段自索引編製作業中排除。

var containerProperties = new ContainerProperties(id: "excludedPathCollection", partitionKeyPath: "/pk" );
containerProperties.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" });
containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/nonIndexedContent/*");
Container container = await this.cosmosDatabase.CreateContainerAsync(containerProperties);

如需詳細資訊,請參閱 Azure Cosmos DB 索引編製原則

輸送量

測量並調整為較低的 RU/秒的使用量

Azure Cosmos DB 提供豐富的資料庫作業。 這些作業包括使用通用磁碟格式 (UDF)、預存程序和觸發程序進行關聯式和階層式查詢,而這些作業全都是對資料庫集合內的文件來進行。

與上述各項作業相關聯的成本,會因為完成作業所需的 CPU、IO 和記憶體而有所不同。 您不需要考慮和管理硬體資源,您可以將要求單位想成是執行各種資料庫作業以及服務應用程式要求時所需的資源數量。

輸送量是根據為每個容器所設定的要求單位數量來佈建。 要求單位消耗量是以每秒多少單位的速率來計算。 如果應用程式的速率超過為其容器佈建的要求單位速率,便會受到限制,直到該速率降到容器的佈建層級以下。 如果您的應用程式需要較高的輸送量,您可以藉由佈建其他的要求單位來增加輸送量。

查詢的複雜性會影響針對作業所耗用的要求單位數目。 述詞數目、述詞性質,UDF 檔案數目以及來源資料集的大小,全都會影響查詢作業的成本。

若要測量任何作業 (建立、更新或刪除) 的負荷,請檢查 x-ms-request-charge 標頭 (或 ResourceResponse<T> 中的同等 RequestCharge 屬性,或 .NET SDK 中的 FeedResponse<T>) 來測量作業所耗用的要求單位數量:

// Measure the performance (Request Units) of writes
ItemResponse<Book> response = await container.CreateItemAsync<Book>(myBook, new PartitionKey(myBook.PkValue));
Console.WriteLine("Insert of item consumed {0} request units", response.RequestCharge);
// Measure the performance (Request Units) of queries
FeedIterator<Book> queryable = container.GetItemQueryIterator<ToDoActivity>(queryString);
while (queryable.HasMoreResults)
    {
        FeedResponse<Book> queryResponse = await queryable.ExecuteNextAsync<Book>();
        Console.WriteLine("Query batch consumed {0} request units", queryResponse.RequestCharge);
    }

在此標頭中傳回的要求費用是佈建輸送量的一小部分 (也就是 2000 RU/秒)。 例如,如果前述查詢傳回 1,000 份 1KB 文件,作業成本會是 1,000。 因此在一秒內,伺服器在對後續要求進行速率限制前,只會接受兩個這類要求。 如需詳細資訊,請參閱要求單位要求單位計算機

處理速率限制/要求速率太大

當用戶端嘗試超過為帳戶保留的輸送量時,伺服器的效能不會降低,而且不會使用超過保留層級的輸送量容量。 伺服器會事先以 RequestRateTooLarge (HTTP 狀態碼 429) 結束要求。 伺服器會傳回 x-ms-retry-after-ms 標頭,以毫秒為單位表示使用者必須先等待多少時間,才能再次嘗試要求。

    HTTP Status 429,
    Status Line: RequestRateTooLarge
    x-ms-retry-after-ms :100

SDK 全都隱含地攔截這個回應,採用伺服器指定的 retry-after 標頭,並重試此要求。 除非有多個用戶端同時存取您的帳戶,否則下次重試將會成功。

如果您有多個用戶端不斷逐漸地以高於要求速率的方式運作,則用戶端內部目前設定為 9 的預設重試計數可能會不敷使用。 在此情況下,用戶端會對應用程式擲回狀態碼為 429 的 CosmosException。

您可以在 CosmosClientOptions 執行個體上設定 RetryOptions,以變更預設的重試計數。 根據預設,如果要求繼續以高於要求速率的方式運作,則會在累計 30 秒的等待時間後傳回 CosmosException (狀態碼 429)。 即使目前的重試計數小於最大重試計數,這項錯誤會也會傳回,無論目前的值是預設的 9 或使用者定義值。

自動化重試行為可協助改善大部分應用程式的復原能力和可用性。 但是在執行效能基準測試時,這可能不是最佳的行為,尤其是在測量延遲的時候。 如果實驗達到伺服器節流並導致用戶端 SDK 以無訊息模式重試,則用戶端觀察到的延遲將會突然增加。 若要避免效能實驗期間的延遲尖峰,請測量每個作業所傳回的費用,並確保要求是以低於保留要求速率的方式運作。

如需詳細資訊,請參閱要求單位

設計較小型的文件以達到較高的輸送量

指定作業的要求費用 (也就是要求的處理成本) 與文件大小直接相關。 大型文件的作業成本高於小型文件的作業成本。

下一步

如需用來評估 Azure Cosmos DB 在數個用戶端電腦上達到高效能情節的範例應用程式,請參閱 Azure Cosmos DB 的效能和規模測試

若要深入了解如何針對規模和高效能設計您的應用程式,請參閱 Azure Cosmos DB 的資料分割與調整規模