Best practices for Azure Cosmos DB .NET SDK

APPLIES TO: SQL API

This article walks through the best practices for using the Azure Cosmos DB .NET SDK. Following these practices, will help improve your latency, availability, and boost overall performance.

Watch the video below to learn more about using the .NET SDK from a Cosmos DB engineer!

Checklist

Checked Topic Details/Links
SDK Version Always using the latest version of the Cosmos DB SDK available for optimal performance.
Singleton Client Use a single instance of CosmosClient for the lifetime of your application for better performance.
Regions Make sure to run your application in the same Azure region as your Azure Cosmos DB account, whenever possible to reduce latency. Enable 2-4 regions and replicate your accounts in multiple regions for best availability. For production workloads, enable automatic failover. In the absence of this configuration, the account will experience loss of write availability for all the duration of the write region outage, as manual failover will not succeed due to lack of region connectivity. To learn how to add multiple regions using the .NET SDK visit here
Availability and Failovers Set the ApplicationPreferredRegions or ApplicationRegion in the v3 SDK, and the PreferredLocations in the v2 SDK using the preferred regions list. During failovers, write operations are sent to the current write region and all reads are sent to the first region within your preferred regions list. For more information about regional failover mechanics see the availability troubleshooting guide.
CPU You may run into connectivity/availability issues due to lack of resources on your client machine. Monitor your CPU utilization on nodes running the Azure Cosmos DB client, and scale up/out if usage is very high.
Hosting Use Windows 64-bit host processing for best performance, whenever possible.
Connectivity Modes Use Direct mode for the best performance. For instructions on how to do this, see the V3 SDK documentation or the V2 SDK documentation.
Networking If using a virtual machine to run your application, enable Accelerated Networking on your VM to help with bottlenecks due to high traffic and reduce latency or CPU jitter. You might also want to consider using a higher end Virtual Machine where the max CPU usage is under 70%.
Ephemeral Port Exhaustion For sparse or sporadic connections, we set the IdleConnectionTimeout and PortReuseMode to PrivatePortPool. The IdleConnectionTimeout property helps which control the time unused connections are closed. This will reduce the number of unused connections. By default, idle connections are kept open indefinitely. The value set must be greater than or equal to 10 minutes. We recommended values between 20 minutes and 24 hours. The PortReuseMode property allows the SDK to use a small pool of ephemeral ports for various Azure Cosmos DB destination endpoints.
Use Async/Await Avoid blocking calls: Task.Result, Task.Wait, and Task.GetAwaiter().GetResult(). The entire call stack is asynchronous in order to benefit from async/await patterns. Many synchronous blocking calls lead to Thread Pool starvation and degraded response times.
End-to-End Timeouts To get end-to-end timeouts, you'll need to use both RequestTimeout and CancellationToken parameters. For more details on timeouts with Cosmos DB visit
Retry Logic A transient error is an error that has an underlying cause that soon resolves itself. Applications that connect to your database should be built to expect these transient errors. To handle them, implement retry logic in your code instead of surfacing them to users as application errors. The SDK has built-in logic to handle these transient failures on retryable requests like read or query operations. The SDK will not retry on writes for transient failures as writes are not idempotent. The SDK does allow users to configure retry logic for throttles. For details on which errors to retry on visit
Caching database/collection names Retrieve the names of your databases and containers from configuration or cache them on start. Calls like ReadDatabaseAsync or ReadDocumentCollectionAsync and CreateDatabaseQuery or CreateDocumentCollectionQuery will result in metadata calls to the service, which consume from the system-reserved RU limit. CreateIfNotExist should also only be used once for setting up the database. Overall, these operations should be performed infrequently.
Bulk Support In scenarios where you may not need to optimize for latency, we recommend enabling Bulk support for dumping large volumes of data.
Parallel Queries The Cosmos DB SDK supports running queries in parallel for better latency and throughput on your queries. We recommend setting the MaxConcurrency property within the QueryRequestsOptions to the number of partitions you have. If you are not aware of the number of partitions, start by using int.MaxValue which will give you the best latency. Then decrease the number until it fits the resource restrictions of the environment to avoid high CPU issues. Also, set the MaxBufferedItemCount to the expected number of results returned to limit the number of pre-fetched results.
Performance Testing Backoffs When performing testing on your application, you should implement backoffs at RetryAfter intervals. Respecting the backoff helps ensure that you'll spend a minimal amount of time waiting between retries.
Indexing The Azure Cosmos DB indexing policy also allows you to specify which document paths to include or exclude from indexing by using indexing paths (IndexingPolicy.IncludedPaths and IndexingPolicy.ExcludedPaths). Ensure that you exclude unused paths from indexing for faster writes. For a sample on how to create indexes using the SDK visit
Document Size The request charge of a specified operation correlates directly to the size of the document. We recommend reducing the size of your documents as operations on large documents cost more than operations on smaller documents.
Increase the number of threads/tasks Because calls to Azure Cosmos DB are made over the network, you might need to vary the degree of concurrency of your requests so that the client application spends minimal time waiting between requests. For example, if you're using the .NET Task Parallel Library, create on the order of hundreds of tasks that read from or write to Azure Cosmos DB.
Enabling Query Metrics For additional logging of your backend query executions, you can enable SQL Query Metrics using our .NET SDK. For instructions on how to collect SQL Query Metrics visit
SDK Logging Use SDK logging to capture additional diagnostics information and troubleshoot latency issues. Log the diagnostics string in the V2 SDK or Diagnostics in v3 SDK for more detailed cosmos diagnostic information for the current request to the service. As an example use case, capture Diagnostics on any exception and on completed operations if the Diagnostics.ElapsedTime is greater than a designated threshold value (i.e. if you have an SLA of 10 seconds, then capture diagnostics when ElapsedTime > 10 seconds ). It is advised to only use these diagnostics during performance testing.

Best practices when using Gateway mode

Increase System.Net MaxConnections per host when you use Gateway mode. Azure Cosmos DB requests are made over HTTPS/REST when you use Gateway mode. They're subject to the default connection limit per hostname or IP address. You might need to set MaxConnections to a higher value (from 100 through 1,000) so that the client library can use multiple simultaneous connections to Azure Cosmos DB. In .NET SDK 1.8.0 and later, the default value for ServicePointManager.DefaultConnectionLimit is 50. To change the value, you can set Documents.Client.ConnectionPolicy.MaxConnectionLimit to a higher value.

Best practices for write-heavy workloads

For workloads that have heavy create payloads, set the EnableContentResponseOnWrite request option to false. The service will no longer return the created or updated resource to the SDK. Normally, because the application has the object that's being created, it doesn't need the service to return it. The header values are still accessible, like a request charge. Disabling the content response can help improve performance, because the SDK no longer needs to allocate memory or serialize the body of the response. It also reduces the network bandwidth usage to further help performance.

Next steps

For a sample application that's used to evaluate Azure Cosmos DB for high-performance scenarios on a few client machines, see Performance and scale testing with Azure Cosmos DB.

To learn more about designing your application for scale and high performance, see Partitioning and scaling in Azure Cosmos DB.

Trying to do capacity planning for a migration to Azure Cosmos DB? You can use information about your existing database cluster for capacity planning.