Cosmos DB doesn’t actually replicate writes across regions instantly; it uses a conflict-resolution mechanism to ensure consistency while allowing writes everywhere.
Let’s see this in action. Imagine you have a products collection with a productId as the partition key.
// Document 1 in products collection
{
"id": "prod-123",
"productId": "prod-123",
"name": "Super Widget",
"price": 19.99,
"region": "East US"
}
Now, let’s say you have two regions enabled for writes: "East US" and "West US".
Scenario: Concurrent Updates
A user in "East US" updates the price to 21.99. Simultaneously, a user in "West US" updates the price to 20.99.
-
East US Client:
PUT /dbs/my-db/colls/products/docs/prod-123 Content-Type: application/json If-Match: "*" // Or a specific ETag { "id": "prod-123", "productId": "prod-123", "name": "Super Widget", "price": 21.99, "region": "East US" } -
West US Client:
PUT /dbs/my-db/colls/products/docs/prod-123 Content-Type: application/json If-Match: "*" // Or a specific ETag { "id": "prod-123", "productId": "prod-123", "name": "Super Widget", "price": 20.99, "region": "West US" }
Cosmos DB receives both requests. It doesn’t block one while the other is processed globally. Each region processes its local write request. Because productId is the partition key, and the id is the same document, a conflict arises.
Conflict Resolution: The Last Writer Wins (by default)
By default, Cosmos DB uses "Last Writer Wins" (LWW) based on the UTC timestamp of the operation. The request that arrives at the internal quorum first, with the later timestamp, will be the one that is committed. The other write will result in a 409 Conflict response to the client that sent it.
If you query the document from "East US" immediately after both operations, you might see:
{
"id": "prod-123",
"productId": "prod-123",
"name": "Super Widget",
"price": 21.99, // Or 20.99, depending on which write "won"
"_rid": "...",
"_ts": 1678886400, // Unix timestamp
"_etag": "...",
"_self": "...",
"_attachments": "...",
"_ts": 1678886400 // This is the crucial timestamp for LWW
}
The _ts field is critical. It’s an internal timestamp generated by Cosmos DB. The write operation whose _ts value is the latest will be the one that ultimately prevails. The client that sent the older timestamped write will receive a 409 Conflict response.
Enabling Multi-Region Writes
To enable multi-region writes, you configure your Cosmos DB account through the Azure portal, Azure CLI, or ARM templates.
-
Azure Portal:
- Navigate to your Cosmos DB account.
- Under "Settings," select "Replicate data globally."
- Choose your desired "Write regions."
- Click "Save."
-
Azure CLI:
az cosmosdb update --name <your-cosmos-db-account-name> \ --resource-group <your-resource-group-name> \ --locations regionName='East US' isWritable=True \ regionName='West US' isWritable=TrueThis command adds "West US" as a writable region alongside "East US." If "West US" was already present but not writable,
isWritable=Truemakes it so. If it wasn’t present, it adds it and makes it writable.
The Problem This Solves: Global Availability and Low Latency
The primary benefit is having your data geographically distributed, allowing users in different parts of the world to read and write data with low latency. If one region experiences an outage, other regions can continue serving traffic.
How it Works Internally: Quorum and Conflict Resolution
When multi-region writes are enabled, Cosmos DB establishes a quorum for writes in each logical partition. For a write to be considered successful, it must be acknowledged by a majority of the replicas within that logical partition across the configured write regions.
- Consistency Levels: Your chosen consistency level (e.g., Strong, Bounded Staleness, Session, Consistent Prefix, Eventual) influences how this quorum is established and how stale reads might be. With strong consistency, a write must be acknowledged by a majority of all regions (read and write) for the write to succeed globally and for subsequent reads to be strongly consistent. For other levels, the quorum is smaller.
- Conflict Resolution: If multiple clients write to the same document in different regions concurrently, Cosmos DB detects this. The default LWW mechanism uses the internal
_tsfield. If you need more sophisticated conflict resolution (e.g., merging data, prioritizing one region’s update), you can implement a custom conflict-free replicated data type (CRDT) or use a dedicated conflict-resolution policy. For example, you could define a stored procedure that, upon detecting a conflict (a409response), reads both conflicting versions and merges them based on application-specific logic before retrying the write.
The One Thing Most People Don’t Know: Write Latency is Not Uniform
While you gain the ability to write to any region, the latency of a write operation is not simply the latency to the nearest region. For operations requiring a quorum beyond a single region (which is common for most consistency levels beyond Eventual), the write must propagate to multiple regions and achieve acknowledgment. This means a write in "East US" might be acknowledged only after it has successfully reached a quorum that includes replicas in "West US" or even "North Europe," depending on your configuration and consistency level. This is why testing write latency from all your client locations is crucial.
The next thing you’ll likely encounter is handling the 409 Conflict responses gracefully, either by retrying with a backoff strategy or by implementing custom conflict resolution logic.