Azure Cosmos DB: A Primer

By Brian Rush, Senior Software Engineer, Capax Global

brianmrush
Hitachi Solutions Braintrust
10 min readOct 8, 2018

--

What is Azure Cosmos DB:

Azure Cosmos DB is a global distributed, multi-model database. A common term in the industry is a NoSQL database. Like many traditional NoSQL databases, Azure supports JSON schema-less structures but it also supports a few others that we will get into.

Key Features of Azure Cosmos DB

Global Distribution

With a click of a button in Azure, data stored in Cosmos DB can be distributed to numerous Azure regions. This allows for storing data at various locations in order to achieve low latency when accessing the data.

Multiple Data Models and APIs

Accessing and querying data stored in Azure Cosmos DB is straightforward and supports multiple common APIs. In addition, Cosmos DB supports multiple storage models, each of which has its advantages and use cases for applications.

The following is a list of the storage models available to Cosmos DB

Data within these storage mechanisms can be accessed with the following

Scale

Cosmos DB allows for both scaling Request Units for scaling the latency of documents requests. In addition, the storage mechanism by which the data is stored can be scaled. All this is provided through a simple configuration in the Azure portal. The scale of storage is handled for you by Cosmos DB transparently. Cosmos DB can be scaled horizontally on a global level. All the intricacies of scaling out are handled for you.

High Availability

Cosmos DB guarantees an end-to-end low latency at the 99th percentile. The benchmark that Cosmos DB guarantees for reads is 10ms for reads on 1KB records and 15ms on writes. On average though the latency is lower (under 5ms). Likewise, Cosmos DB has a 99.99 percent availability SLA for all single region database accounts and a 99.999 percent read availability on all multi-region databases.

Choice of Data Consistency Models

When talking about data in NoSQL databases a common concept that you will hear about is the CAP Theorem. The CAP theorem says that only two of the three items below can be guaranteed in a distributed storage system (Cosmos DB being one of them).

  • Consistency: Every read receives the most recent write or an error
  • Availability: Every request receives a (non-error) response — with the guarantee that it contains the most recent write
  • Partition tolerance: The system continues to operate despite an arbitrary number of messages being dropped (or delayed) by the network between nodes

That being said Cosmos DB offers 5 consistency models to cover the spectrum. Sometimes are applications may need to must up to date data. In that case, consistency is much more important. Other times our applications may not need the most up to date data. In that case, consistency is not as important. The choices below allow us to configure Cosmos DB to consistency needs of our application.

Here is a brief description of what each consistency model offers

  • Strong: Reads are guaranteed to return the most recent version of an item.
  • Bounded Staleness: Guarantees that the reads may lag behind writes by at most K versions or prefixes of an item or t time-interval.
  • Session: Consistent Prefix. Monotonic reads, monotonic writes, read-your-writes, write-follows-reads. The key is that the data is scoped to the client session.
  • Consistent Prefix: Updates returned are some prefix of all the updates, with no gaps
  • Eventual: Out of order reads. In other words, not all clients may see the same data but they eventually will.

The default consistency and most common is Session. The consistency level is set the Azure portal located in the following location.

So now that we reviewed what Cosmos DB is, the consistency models, the storage models and the available APIs, lets drill a little deeper on some important concepts within Cosmos DB Storage and Partition Keys.

Within Cosmos DB the containers for starting data are called collections for documents, graphs or tables. The containers are logical resources and can span one or more physical partitions and/servers. The number of partitions required to store the data and how that storage is allocated is handled for us by Cosmos DB. Pretty sweet because that is complex stuff that is handled for us transparently. That being said there are a few very important decisions we need to make when setting up our collections. The decisions are

1) Type Storage Container: There are two types. Fixed and Unlimited. Fixed is limited to data up to 10 gigs. Also the fixed storage does not need a partition key. Unlimited is just that, unlimited. When choosing unlimited, the choice of partition key is VERY important.

2) Partition Key: The is a VERY important decision and has to be made up front. You can’t can’t change the partition key once the collection is established. So what is a partition key? Each document must have a partition key and a row key, which uniquely identify it. Your partition key acts as a logical partition for your data and provides Azure Cosmos DB with a natural boundary for distributing data across physical partition. When accessing and querying data from Cosmos DB, the partition key plays an important role. There is an intelligent hashing algorithm around the partition key that will inform where the data resides. It’s a best practice to have a partition key with a large number of distinct values (e.g., hundreds or thousands). It lets you distribute your workload evenly across these values. An ideal partition key is one that appears frequently as a filter in your queries and has sufficient cardinality to ensure your solution is scalable. Visually this looks something like the following. Lets for a moment imagine we have a Comsos DB for airport flight data. A potentially good partition key would be the airport id. This way our data is evenly distributed and when we query the data, airport is likely always on the query parameters. This way Cosmos DB will now how and where to access the relevant data efficiently

3) Throughput RUs: At any scale, you can store data and provision throughput capacity. Each container is billed hourly based on the amount of data stored (in GBs) and throughput reserved in units of 100 RUs/second, with a minimum of 400 RUs/second. Unlimited containers have a minimum of 100 RUs/second per partition.Note that the RU values can be changed later on. Microsoft has has a nice tool located here to help determine what the cost and setting or RUs should be. There is definitely both an art and science to tuning RUs optimally. Now that we know these are the decisions we need to make, this is where we set that within the Azure portal

So the next thing you may to start to think about these type of items

  • How is the data always available?
  • How is the data replicated across all the partitions
  • How is fail over handled if I have regions, partitions that go bad.

First, the following diagrams depicts how partitions stored in 3 regions are kept in sync.

So, the main write partition will receive data, then under the hood Cosmos DB will handle replicating that data to the other partitions in the East and North Europe regions.

Within the Azure portal we can specify how many regions we want for our data and how fail over is handled.

Let’s take a brief look at the anatomy of all the elements in a Cosmos DB. These are the main components you will work working with when you are in and out of your database.

Modeling Data in NoSQL database

It’s probably worth mentioning at this point that modeling data within a NoSQL database requires thought and a different mindset of traditional RDMS databases. First, the data is schema-less. One document can have a completely different set of elements than the next. I tend to think of each to think of each document as a mini database in itself.

This is a sample of a Document in a collection called Person. In a relation database model, addresses and contact details would likely be a separate set of tables. In NoSQL world we actually store that data right with the person. This way there are no joins to other tables. Simply pull that document out and read the relevant information. It’s important to note that in the Cosmos DB world, it is not possible to join collections together in the sense of a SQL join. Now this can be taken to extremes. Take for example a document that stores product information. Along with the production information, we may want to store product reviews or comments. One may think that that information would be stored inside the product document but that can be problematic. In the Cosmos DB world, this would cause a “hot partition” if our products were receiving lots of comments. In other words, for every comment, we would have to open the document, save the comment. That process rinses and repeats for every comment. Probably not the most efficient way to store the information. It may be better to store comments in their own collection with some identifier that can link it back to a product.

All of the surmises to modeling data in NoSQL requires a different mindset.

Document Indexing

A natural progression from modeling data structures in NoSQL revolves around indexing that data for fast retrieval. The good news is that in Cosmos DB that is handled for us by default. Every document is indexed for us. Now we can override and tailor the default indexing strategy. There is a great article located here that explains indexing in detail.

Within the Azure portal, this is where we can set our partition key as well as any custom indexing. Full details on how indexing works in Cosmos DB can be found here.

They key point is that we have full control over how our documents are indexed which in turn keeps our queries running optimally.

SQL Query of Documents

As we stated before there are numerous APIs that allow us to access and query our documents. This next section is going to show a few examples of the SQL api and how to query documents.

First, within the Azure portal you can query documents using a tool similar to SSMS.

In the example above, we opened the New SQL Query tool, wrote a sample select statement using SQL syntax in order to retrieve a document from the TableRows collection. Most of the common SQL statements are available to the SQL API. Note that not every SQL command is available. A complete list of the SQL commands supported can be found here.

An important concept to note, and one that differs from traditional RDMS, is that we can’t join collections together. When we run joins we are really running them against sub documents within our documents within the same collection.

The following in an example of a self join that then reshapes the return to create a new document format.

The right hand side represents an example document within the collection that we will be joining against. The top left is the SQL statement in which we are doing a join against the lines portion of the document. The bottom left represents the reshaped document results after the query has been run.

Another way to access and query the data is through C#. There is a client SDK which allows for our C# applications to connect and query Cosmos DB. The NuGet package is located here.

There is a very detailed set of documentation on how to use the client SDK located here along with a lot of examples. The following is a few snippets of code on how to interface with Cosmos DB from C#.

This shows a sample SQL query against Cosmos DB:

This is an example of an upsert of a document stream into Cosmos DB:

Conclusion

Cosmos DB can help you build a globally distributed, multi-model database with Azure. Its ability to elastically scale globally, with transparent horizontally-partitioning, and multi-master replication, is unparalleled. I would love to hear how you are using Cosmos DB; if you have any insights or questions please comment below.

--

--