Cosmos DB is Microsoft’s new NoSQL store released in the Azure cloud. Unlike relational databases, it is scalable as it is a hosted database service, so it enjoys a lot of popularity among high transaction .NET and .NET Core applications. However, using Cosmos DB, you need to be wary of performance bottlenecks and cost overhead for accessing the database, as Microsoft charges you for each transaction to the database.
While Cosmos DB is scalable in terms of transaction capacity, but it is not as fast because the database service is living in a separate VNet or subscription compared to the applications. So even if your applications are running in the Azure cloud, accessing the database across the VNet will cause a huge blow to the performance.
In order to tackle these two issues, it is ideal to introduce caching into your Cosmos DB application. You’ll see a drastic improvement in your application performance and at the same time, a significant reduction in operational cost because 80-90% of the time, your application will be fetching data from the cache instead of the database.
NCache Details Sync Cache with Cosmos DB Use Caching with Cosmos DB-Webinar
Using Caching with Cosmos DB
The following code snippet explains how to use caching with Cosmos DB. Supposedly, a Cosmos DB instance contains a collection of Customers.
- Search for the specified customer in the cache based on the cache key.
- If the item is not in the cache, query Cosmos DB to search for the customer.
- If the customer exists in the database collection, retrieve the item.
- Add the specified customer to the cache with an expiration value of 5 minutes to ensure data consistency.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// Generate a unique cache key string key = $"Customer:ALFKI"; // First look for data in cache var retrievedItem = cache.Get<Customer>(key); // If not found in the cache, fetch data from the database and add it to the cache if (retrievedItem == null) { // New instance of CosmosClient class using a primary connection string CosmosClient client = new CosmosClient("connection-string-from-portal"); // Get container object Container container = client.GetContainer("Northwind", "Customer"); // Create partition key and id // Here, the id is CustomerID and Partition Key is City in the Customer class PartitionKey partitionKey = new PartitionKey("Seattle"); String id = "ALFKI"; // Read item from the container using the id and partitionKey var itemResponse = container.ReadItemAsync<Customer>(id, partitionKey).Result; // get customer object from database response Customer customer = itemResponse.Resource; // Initialize cache item with customer data and set expiration var cacheItem = new CacheItem(customer); cacheItem.Expiration = new Expiration(ExpirationType.Absolute, TimeSpan.FromMinutes(5)); // Insert cacheItem in cache against the given key cache.Insert(key, cacheItem); } |
NCache Details Notification Extensible Dependency NCache Docs
Using NCache as a Distributed Cache with Cosmos DB
When working with Cosmos DB, it is most likely that your application is a high transaction application running in a multi-server environment through a load balancer, making abundant database calls. Moreover, a standalone cache will not be possible in this environment, so you need a distributed cache like NCache between the application and the database.
A distributed cache allows you to add more cache servers as your transactional load grows, so the cache never becomes a bottleneck. Hence, the number of your application servers doesn’t matter because you can have sufficient cache servers between the application and the database, unlike a relational database which is a major choking point for any scalability.
While Cosmos DB scales much more efficiently than a relational database, it is still no match for an in-memory distributed cache like NCache that sits with your application’s VNet. In fact, a portion of the cache will reside within the application process itself (called a client cache), giving you inProc caching speed.

Figure 1: Using NCache to cache Cosmos DB data
NCache Details Cache Operations in NCache NCache Docs
Caching Collection of Database Items
By using a distributed cache, you can enhance your Cosmos DB application’s performance exceedingly by reducing database trips across the network, especially for read operations. Thus, while you can retrieve single entities from the database, a far more economical approach in terms of throughput and reduced R/Us (Request per Units) is to retrieve the collection of items from the database and apply the operations at the caching tier.
For this purpose, NCache allows the caching of collection as a single cached item along with caching the individual elements of the collection, each against its own designated cache key. Any changes to the state of the collection can later be pushed to the database at the end of the operations.
NCache Details Sync Cache with Cosmos DB NCache Docs
Cache Collection as Single Item
You can cache the collection as a single item if you want to load the collection items collectively, for example, all German customers. You can query Cosmos DB for all customers in Germany and return the results as a single list which can then be added to the cache for further use.
The following code sample shows how to do this for retrieving the list of German customers from the database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
string key = $"CustomersFromGermany"; // First look for data in cache IDistributedList<Customer>germanCustomers = cache.DataTypeManager.GetList<Customer>(key); // If not found in the cache, fetch data from the database and add it to the cache if (germanCustomers == null) { // Create a query var query = new QueryDefinition("SELECT * FROM Customers c WHERE c.Country = 'Germany'"); // Get query iterator FeedIterator<Customer>feedIterator = container.GetItemQueryIterator<Customer>(query); // Specify expiration attribute for List var attributes = new DataTypeAttributes(); attributes.Expiration = new Expiration(ExpirationType.Absolute, TimeSpan.FromMinutes(5)); // Create a list to store customers as a collection germanCustomers = cache.DataTypeManager.CreateList<Customer>(key, attributes); // Read DB data using feed while (feedIterator.HasMoreResults) { var response = feedIterator.ReadNextAsync().Result.Resource; foreach (Customer customer in response) { germanCustomers.Add(customer); } } } |
NCache Details Expiration in Cache Cache Operations in NCache
Cache Collection Items Separately
You can associate metadata with cache items in NCache to categorize data through unique identifiers such as tags. In this way, you can retrieve multiple items from the cache against a single identifier, for example, customers belonging to Germany.
To achieve this, you can query for German customers in Cosmos DB and associate a tag such as a Customer: Country: Germany against the resultant items. Caching these items separately, will make them available for various query combinations and even faster fetches of a single customer.
Using the previous example, we first search the cache for customers with the tag Customer: Country: Germany. If items do not exist in the cache, query Cosmos DB for items in the Customer collection- having their “Country” attribute specified as “Germany”. However, since we now want to cache the collection items separately, we do the following:
- Once you fetch the items from the database, specify the expiration value for the items.
- Specify tag Customer: Country: Germany against each cache item.
- Add items to the cache in bulk.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// Create a dictionary to add bulk items in the cache var collectionItems = new Dictionary<string, CacheItem>(); CacheItem cacheItem = null; var expiration = new Expiration(ExpirationType.Absolute, TimeSpan.FromMinutes(5)); // Read DB data using feed while (feedIterator.HasMoreResults) { var response = feedIterator.ReadNextAsync().Result.Resource; foreach (Customer customer in response) { cacheItem = new CacheItem(customer); cacheItem.Expiration = expiration; //Create a unique key for each item in collection string itemKey = $"Customer:{customer.CustomerID}"; // Add cacheItem to dictionary collectionItems.Add(itemKey, cacheItem); } } // Insert customer collection items seperately using bulk operation if (collectionItems.Count > 0) { cache.InsertBulk(collectionItems); } |
NCache Details Tags in Cache Cache Operations in NCache
NCache Deployment in Azure
Major cloud marketplaces offer NCache, such as Azure and AWS, and downloading for on-site use. For all other cloud systems, you can download and install NCache on a virtual machine in a model of Bring Your Own License (BYOL). NCache is deployed in Azure in the following ways:
- Deploy NCache Cloud in Azure
- Deploy NCache as Virtual Machines
- Using NCache in a Platform-as-a-Service (PaaS) offering in Azure.
For more detail on these options, have a look at Cloud Deployment Options for NCache.
NCache Details NCache in AWS NCache Cloud Service
Conclusion
To sum it up, introducing caching in your Cosmos DB application enhances speed, reliability, and availability. By using NCache with Cosmos DB, there is a major boost in the application’s performance because the cache resides within the application process. Secondly, a drastic reduction in cost as 80-90% of your data is accessible without making costly database trips to Cosmos DB.