Sharding Strategies / Training

What You'll Learn

Identify the Optimal Shard Key for Your Application: Implement the optimal shard key and data distribution option for your application's requirements.
Shard Keys

When partitioning a collection, the shard key is the core mechanism MongoDB uses to distribute a collection across shards, ensuring data is organized efficiently.

The purpose of a shard key is to evenly distribute read and write operations across all shards—at scale. Additionally, read operations should target the lowest number of shards possible. Achieving this goal reduces latency for important queries.

To do this, be sure to carefully analyze critical query patterns and potential shard key candidates.

To achieve an optimal shard key, let’s look at the different parts of a shard key and how they affect the sharding of a collection.

Breaking Down Shard Keys

As we mentioned before, partitioning a collection is implemented via the shardCollection command. This is how you shard a collection with your selected shard key. The two fields that determine the design of a shard key contain the shard key field(s) and the distribution option:

Note
Every sharded collection must have a shard key defined, and the shard key must be indexed. With an index supporting the shard key, MongoDB can efficiently process queries, sort data, and enforce constraints. This significantly enhances performance, especially for large datasets.
Let’s first look at the shard key field.
Shard Key Field

When you use the shardCollection command, you designate one or more fields, represented as <field1>, <field2>, and so on, to act as the shard key. These fields are pivotal in the distribution process. Every document in the collection gets mapped based on the values of these fields. Therefore, a good shard key must be granular enough to ensure effective distribution.

In the following short video, we’ll examine a document from the LeafyBank messages collection to determine the shard key field.

Select Play to learn more.
Press O for more options
Video Thumbnail
1:30


 Video Transcript (English)

Here we have an example document from LeafyBank’s messages collection.

LeafyBank could choose any of these fields as a shard key to shard data on. But each choice comes with benefits and tradeoffs.

For example, using timestamp as a shard key with { timestamp: 1 } might seem useful for chronological access patterns, like retrieving the latest notifications of customer credit card transactions to detect fraud.

However, it can lead to uneven insert distribution, with recent timestamps concentrating on one shard.

They could also choose a compound shard key like { userId: 1, category: 1 }.

This shard key uses multiple fields to influence data distribution, which can improve query efficiency when both fields are frequently queried together. However, adding the field, category, might overcomplicate matters as it could lead to more fragmented query paths and increased complexity in balancing the shard load.
If access patterns primarily focus on users, a single-field shard key like { userId: 1 } is sufficient as long as the field has a high cardinality. It efficiently distributes data by user, ensuring queries that target user messages are optimally routed.

For LeafyBank, userId would be a great shard key to select.
Choosing a shard key field can seem complicated. Fortunately, there are key characteristics and other metrics you can use to assess the effectiveness of a shard key.
Key Characteristics of an Effective Shard Key
We’ll focus on a few key characteristics for assessing shard keys: cardinality, frequency, monotonicity, read distribution, and write distribution.
Select each key characteristic to learn more.
Cardinality

The cardinality of a shard key indicates how many pieces, or ranges, of data can be created. This affects how well the collection can grow. It's best to choose shard keys with many unique values (high cardinality), as keys with fewer unique values (lower cardinality) can limit growth and performance.

Frequency

A shard key's frequency shows how often its values appear. High-frequency values can create bottlenecks, which limits scalability.

Monotonicity

In the context of sharding, monotonicity refers to how a shard key's values either consistently increase or decrease over time. If a key is monotonic, write inserts tend to accumulate in one chunk, potentially causing uneven distribution and performance issues.

Read Distribution

Read distribution provides insights into how read operations are distributed across the shards in a cluster. When running the analyzeShardKey command, which we will cover later, the readWriteDistribution metric includes helpful sub-metrics, specifically:

  • percentageOfSingleShardReads: Shows how many reads target a single shard. This is the fastest way to read data because it avoids extra work.
  • percentageOfMultiShardReads: Shows how many reads target multiple shards. This takes more time and resources because the mongos has to combine the results.
  • percentageOfScatterGatherReads: Shows how many reads check every shard. This is usually the slowest and uses the most resources.
  • numReadsByRange: Shows number of times each range is targeted. Avoid a shard key where the distribution of numReadsByRange is very skewed since that implies that there is likely to be one or more hot shards for reads.

Ideally, the upper limit of percentageOfMultiShardReads and percentageOfScatterGatherReads should be a combined 5-10%.

Write Distribution

Write distribution provides insights into how write operations are distributed across the shards in a cluster. When running the analyzeShardKey command, which we will cover later, the readWriteDistribution metric includes helpful sub-metrics, specifically:

  • percentageOfSingleShardWrites: Shows how many writes target one shard. This is the fastest way to insert data.
  • numWritesByRange: Shows the number of times that each range is targeted. Avoid a shard key where the distribution of numWritesByRange is very skewed since that implies that there is likely to be one or more hot shards for writes.
  • percentageOfShardKeyUpdates: Measures the percentage of updates that modify shard key values, which can incur costs due to potential cross-shard moves.
  • percentageOfSingleWritesWithoutShardKey & percentageOfMultiWritesWithoutShardKey: Shows percentage of writes without a shard key, which is a scatter-gather query. Find a shard key that lets most of your mission critical queries target a single shard.
Distribution Options
The second aspect of designing a shard key is the distribution option. These options include ranged, hashed, and zoned sharding. The most common option is ranged, but there are use cases for hashed. You can use zoned sharding with either distribution option.
Select each distribution option to learn more.
Ranged

Ranged sharding in MongoDB splits data across shards by using a range of shard key values. This makes range queries on the shard key efficient, but requires careful shard key selection to avoid hotspots due to predictable data patterns.

To select this strategy, complete the key field as follows: key: { <field>: 1}.

Example: Imagine a ride-sharing application that needs to manage and efficiently process ride data. Each ride has a field { "region": 1, "rideId": 1 } that records when the ride was requested.

The application can benefit from ranged sharding by using { region: 1, rideId: 1 } as the shard key. Reads and writes that would query by rideId would also need to include region to target the correct shard. This choice would makes range queries on rides per region very efficient. For instance, when generating reports or analyzing patterns such as "number of rides requested in the last month," the queries can quickly access the relevant data across different shards using the range of the { "region": 1, "rideId": 1 }.

Hashed

Hashed sharding in MongoDB uses hashed shard key values to evenly distribute data across shards, preventing uneven inserts. Specifically, hashed sharding takes a natural shard key value, hashes it and creates a new value, and then distributes the inserts back into ranges. In special cases, it's ideal for when a natural shard key happens to be monotonically increasing or decreasing and all inserts would go all in one chunk. However, hashed sharding may not efficiently optimize range queries because it disrupts natural value order.

To select this strategy, complete the key field as follows: key: { <field>: "hashed"}.

Example: Consider an e-commerce application where each document represents an order but orderID is monotonically increasing. By using hashed sharding on the orderID, {orderID: “hashed”}, you can balance write operations across shards. This distribution is beneficial for workloads where inserting orders happens rapidly, ensuring that no single shard becomes a bottleneck due to a high volume of sequential order inserts.

To shard a collection using a hashed shard key, you'll need to create an index on the hashed shard key first. This index is essential as it enables the balancer to distribute data across the shards.

Zoned

Zoned sharding lets global apps store ranges of user data in specific areas (zones), like a continent. This reduces latency by storing and accessing data close to its origin and can help meet data residency requirements.

This strategy can be combined with ranged or hashed sharding by using the addShardtoZone and updateZoneKeyRange commands. To learn how to implement zoned sharding, refer to the MongoDB documentation on Zoning.

Common Issues to Avoid
A poorly selected shard key could result in these three issues: uneven load distribution, scatter-gather queries, and jumbo chunks.
Select each issue to learn more.
Uneven Load Distribution

Uneven load distribution occurs when data or query load is not evenly spread across shards, leading to bottlenecks and hotspots.

If a shard key leads to data being grouped in a way that is not well balanced, certain shards may end up handling significantly more requests or storing disproportionately more data than others.

Scatter-Gather Queries

Scatter-gather queries involve sending a query to multiple shards, followed by collecting and consolidating results from those shards to return a complete result set, resulting in increased overhead and latency.

The choice of a shard key affects how often scatter-gather queries occur. A shard key that aligns with critical queries enables targeted queries, which are routed to specific shards instead of being broadcast to all of them.

Jumbo Chunks

Jumbo chunks occur when a chunk exceeds the maximum size and cannot be split. This is often due to selecting a low cardinality shard key that leads to uneven data distribution.

The balancer can only split jumbo chunks if the shard key is refined. Jumbo chunks can only be moved with user intervention. Choosing a shard key with a high cardinality is important to prevent these situations.

Selecting the Best Shard Key

To analyze shard keys and choose the best one for your application’s workloads, you can use the configureQueryAnalyzer and analyzeShardKey commands. These commands gather metrics to assess the balance, performance, and scalability of potential shard keys based on your application’s most important and frequent queries.

In the following video, we’ll show you how to use these commands to analyze shard keys. We’ll also discuss key characteristics and performance metrics associated with shard keys.

Select Play to learn more.
Press O for more options
Video Thumbnail
7:31
 Video Transcript (English)

In this video, we'll guide you through using the configureQueryAnalyzer and analyzeShardKey commands in MongoDB. Together, these commands operate as a shard key analyzer by providing metrics about shard key performance so that you can make the best choice for your application.

These commands can be run on any cluster, but for now, we'll demonstrate with a MongoDB Atlas cluster using an example from our LeafyBank app.

By the end of this video, we’ll have found an optimal shard key for LeafyBank that aligns with their most critical queries.

First, we enable query sampling using the configureQueryAnalyzer command. This has to be kept enabled for a reasonable amount of time to capture the typical workload.

Let’s examine the 'messages' collection in the LeafyBank app. We'll configure the query analyzer for this collection by setting mode to "full", which analyzes all query types, and samplesPerSecond: 50, sampling 50 queries per second.

For the purpose of this video, assume we have allowed the command to run for a few days. Now we can retrieve sampled queries with the $listSampledQueries aggregation stage.

With these samples, we can see the predominant query patterns. We'll focus on the most critical reads and writes: Retrieve a year’s worth of messages so users can review their statements, notifications, and alerts, Retrieve unread messages so users can catch up on messages, Insert new transaction alerts into the database to keep users informed of account activities in real-time.

Next, we'll use the analyzeShardKey command to evaluate shard key candidates.

This command provides insights into key characteristics and read-write distribution by enabling keyCharacteristics and readWriteDistribution options.

LeafyBank wants to shard the “messages” collection. They will use analyzeShardKey in the MongoDB shell to evaluate their choices.

We will look at {userId: 1} because most of their critical queries query on {userId: 1}.

We will first focus on keyCharacteristics by setting keyCharacteristics to true in the analyzeShardKey command.

Note that the analyzeShardKey needs an index to produce keyCharacteristics. We’ve already done that for {userId: 1}.

We’ll also specify sampleSize as 10,000 to demonstrate that you can run the command only on a subset of documents if needed.

The results give us information about the key characteristics of the shard key candidate. Let’s go through each: cardinality, frequency, monotonicity, and read and write distribution.

For cardinality of the shard key candidate, {userID: 1}, each user has a unique ID. Therefore, this shard key has many values, resulting in high cardinality.

For frequency, the numDistinctValues metric indicates the diversity of user activity over time.

The mostCommonValues can highlight instances of userId that occur frequently. There is some risk with the shard key of userId. Particular users could be power users. A high volume of messages sent to certain users at particular times could create performance bottlenecks by disproportionately concentrating documents in certain chunks.

To evaluate monotonicity, we can look at the monotonicity field in the command’s return.

Here, it indicates that the shard key is deemed "not monotonic," meaning the insertion order of documents does not align predictably with the order of the shard keys.

Lastly, let’s turn our attention to readWriteDistribution of the shard key candidates, {userId: 1}.

We’ll run the analyzeShardKey command again, this time setting readWriteDistribution to true.

First, we’ll focus on our read distribution.

For percentageOfSingleShardReads, our analysis shows that 93.5% of reads target a single shard. This suggests efficient queries.

For percentageOfMultiShardReads, this percentage is 5, meaning multi-shard reads are only a small percentage. Good!

And we are seeing 1.5 percent for percentageOfScatterGatherReads.

Lastly, we see an even distribution of reads across shard key ranges looking at the numReadsbyRange sub-metric.

As for writeDistribution, we are seeing a good distribution as well.

For percentageOfSingleShardWrites: A high percentage indicates efficient, low-latency write operations for LeafyBank, optimizing the insertion of user’s transaction alerts and notifications.

Looking at numWritesByRange, for LeafyBank, evenly distributed writes across shard key ranges ensure user’s messages, alerts, and notifications remain balanced, avoiding performance bottlenecks.

Moving on to percentageOfShardKeyUpdates: A percentage of one percent indicates that there are minimal updates to a document's shard key value, preventing any document migrations to different shards. This is because userIds are rarely changed.

And lastly, for percentageOfMultiWritesWithoutShardKey and percentageOfSingleWritesWithoutShardKey : A percentage of zero here ensures LeafyBank's writes are not using scatter gathers. This means there are no writes that are not using the shard key to find out which documents to update, avoiding scatter-gather overhead and supporting real-time alert delivery.

Having gathered and analyzed these key characteristics and metrics, We’re ready to make a shard key decision.

The shard key candidate { userId: 1 } proves to be an excellent choice for LeafyBank's messages collection, thanks to its favorable characteristics. Its high cardinality, due to the many unique values that come with userId, ensures an even distribution of documents across shards. Additionally, the shard key's non-monotonicity means write inserts will not accumulate in one chunk. We did identify a risk looking at frequency, how power users could cause bottlenecks, but when looking at read-write distribution, we found enough favorable metrics to justify the tradeoff.

Let's review the steps of using the configureQueryAnalyzer and analyzeShardKey commands to identify a suitable shard key. Identify a shortlist of shard key candidates, Run the configureQueryAnalyzer to collect real-world query samples over a few days, providing valuable insights into common query patterns that influence shard key selection, Next, use the analyzeShardKey command to evaluate key characteristics such as cardinality, frequency, and monotonicity, along with read and write distribution metrics.

By synthesizing these comprehensive analyses, you can select a shard key that meets your application's compliance and performance requirements.


Key Points to Remember

Awesome work! Here are some key points to remember as you design an optimal shard key and sharding strategy:

  • Understand the Role of a Shard Key: Choose a shard key that evenly distributes data and operations across shards to improve performance for all database operations.
  • Plan Ahead for Shard Key Selection: Picking the right shard key is crucial for your database's performance and ability to scale. Factor in your application's demands and query styles to avoid uneven data distribution.
  • Select the Right Distribution Options: Ranged sharding is the most common option. Use hashed keys in special cases, like when you have a monotonic shard key and need to evenly distribute writes. You may also zone ranges of data.
  • Use the configureQueryAnalyzer and analyzeShardKey commands: Use these commands to review query patterns and assess shard key options. Check keyCharacteristics and readWriteDistribution to make an informed choice.
Note
Sometimes the choice of a shard key to achieve scale is hard and requires application changes. Consider consulting with MongoDB’s Professional Services.
If the performance of your shard key ever degrades or needs change, don’t worry! MongoDB allows you to change your shard key decisions in easy steps. We’ll cover this next.
Select Next to continue.