Week 8: Sharding & Horizontal Scaling

Replication (Week 7) solves availability — every member holds the full data set. It doesn't solve capacity: once a working set outgrows what one replica set's primary can hold in memory or write to fast enough, the answer is to split the data across multiple replica sets instead. That's sharding — and the single decision that determines whether it works well or badly is the shard key.

Module 8 of 10 Week 8 of 10 ~3 Hours Hands-on Exercise Included

By the end of this week, you'll be able to

  • Explain what a shard key, a chunk and the mongos router each do
  • Recognize a shard key that will create a hot shard, and explain why
  • Distinguish a targeted query from a scatter-gather query, and why the difference matters
  • Decide, for a given workload, whether sharding is actually the right next step

1. Shards, Chunks & mongos

A sharded cluster splits one logical collection's data across multiple shards — each shard is itself a replica set, so sharding and replication compose rather than compete. Three pieces make it work together:

  • Shards — each one holds a subset of the collection's documents, as its own replica set.
  • Chunks — MongoDB splits the collection's range of shard-key values into chunks, and distributes chunks across shards, automatically rebalancing them as data grows.
  • mongos — the router applications actually connect to. It knows which shard(s) hold the chunks relevant to a query and routes accordingly, so application code never talks to a shard directly.
enabling sharding on a database and collection
sh.enableSharding("shop");

sh.shardCollection("shop.orders", { customerId: 1 });
// { customerId: 1 } is the shard key -- every document's shard is
// determined by the value of this field

2. Choosing a Shard Key

The shard key is one or more fields, chosen at the time you shard a collection, that MongoDB uses to decide which chunk — and therefore which shard — a document belongs to. It cannot be changed later without re-sharding the collection, which makes it the single highest-stakes decision in this module.

A good shard key has three properties, and needs all three:

  • High cardinality — many distinct possible values, so chunks can actually be split finely.
  • Even distribution — writes spread roughly evenly across the key's range, not clustered on a narrow band of values.
  • Query isolation — the fields your application's most common queries filter on, so mongos can route to a single shard instead of asking all of them.

3. Hot Shards & Bad Key Choices

The most common sharding mistake is picking a key that's monotonically increasing — an auto-incrementing counter, or a plain ObjectId used on its own (which is itself roughly time-ordered).

a shard key that creates a hot shard
sh.shardCollection("shop.orders", { _id: 1 });
// _id values are roughly time-ordered -- every NEW order's key value is
// higher than every existing one, so every new order lands on the SAME
// chunk, and therefore the SAME shard, until that chunk splits and moves

Every write briefly piles onto one "hot" shard instead of spreading across the cluster — exactly the imbalance sharding was supposed to eliminate. A common fix is a compound shard key that pairs a naturally distributing field with the field queries actually need:

a compound key that spreads writes AND supports common queries
sh.shardCollection("shop.orders", { customerId: 1, _id: 1 });
// customerId spreads writes across many distinct values;
// _id as the second component keeps each customer's chunk ranges ordered

4. Targeted vs. Scatter-Gather Queries

Once a collection is sharded, the shard key you chose also determines how cheap or expensive a given query is to run.

targeted vs. scatter-gather, with shard key { customerId: 1, _id: 1 }
// TARGETED -- includes the shard key, mongos routes straight to one shard
db.orders.find({ customerId: ObjectId("c1") });

// SCATTER-GATHER -- no shard key in the filter, mongos must ask EVERY
// shard and merge the results, even though only a few documents match
db.orders.find({ status: "shipped" });

A scatter-gather query still returns correct results — sharding never changes correctness — but it loses the scaling benefit sharding was meant to provide, since every shard does work regardless of how few of its documents actually match. This is exactly why "query isolation" is one of the three shard-key properties from Section 2: pick a key your dominant query pattern actually filters on.

5. When to Actually Reach for Sharding

Sharding adds real operational complexity — more processes to run, a shard key you can't easily change, scatter-gather queries to watch for — so it's worth reaching for only once replication alone genuinely can't keep up. Signals that usually indicate it's time:

  • The working data set no longer fits comfortably in a single primary's available RAM, causing frequent disk reads and degraded performance.
  • Write throughput is approaching what a single primary can sustain, even after indexing and query optimization.
  • Total data volume is approaching the practical storage limits of a single node.

A replica set that's simply read-heavy is usually better solved with more secondaries and secondaryPreferred reads from Week 7 — sharding is the answer specifically to write throughput or data volume outgrowing a single primary, not to general traffic growth.

Most applications never need to shard

A well-indexed replica set on reasonably provisioned hardware handles a surprisingly large amount of traffic. Treat sharding as a deliberate response to a measured bottleneck, not a default architecture to reach for "to be safe" — the shard key decision is hard to undo, and the added complexity is a real ongoing cost.

6. Hands-on Exercise

Hands-on

Evaluate two shard key candidates for a real workload

No cluster required for this one — the exercise is in reasoning through the tradeoffs, which is where most real shard-key mistakes actually happen.

Requirements:

  1. Given an events collection logging { _id, userId, eventType, createdAt } at high write volume, write out why { createdAt: 1 } alone would create a hot shard.
  2. Propose a compound shard key for events that spreads writes evenly and keeps the application's dominant query — "all events for one user in a date range" — targeted to a single shard. Justify your choice against all three properties from Section 2.
  3. List two query patterns against your chosen key that would still be scatter-gather, and explain why they can't be targeted.
  4. Write a short paragraph arguing whether this events collection should actually be sharded yet, or whether a well-indexed replica set would do, using the signals from Section 5.
Hint

A common answer for step 2 is { userId: 1, createdAt: 1 }userId gives even distribution across many users, and having it as the leading key field means a "this user's events" query is targeted. Compare your reasoning against that, and be explicit about why field order in a compound shard key matters for which queries end up targeted.

7. Knowledge Check

Four quick questions. Expand each to check your answer.

Q1

What is the mongos process, and why does application code connect to it instead of to a shard directly?

mongos is the router that knows which shard (or shards) hold the chunks relevant to a given query, and routes the query accordingly. Applications connect only to mongos, never to individual shards, so the application never needs to know how many shards exist or which one holds which data — that routing logic is entirely mongos's job.

Q2

Why does sharding a collection on { _id: 1 } alone typically create a hot shard?

A default ObjectId is roughly time-ordered, so every newly inserted document's _id is higher than nearly every existing one. That means every new write lands on the same chunk at the high end of the key range — and therefore the same shard — until that chunk splits and migrates, defeating the point of spreading writes across the cluster.

Q3

A query filters on a field that isn't part of the shard key. Is the result still correct? What's the cost?

Yes — sharding never affects correctness, only performance. Without the shard key in the filter, mongos can't determine which shard holds the matching documents, so it sends a scatter-gather query to every shard and merges the results. That costs work on every shard even if only one of them actually holds matching data.

Q4

A replica set is struggling under heavy read traffic, but writes and data volume are both modest. Is sharding the right fix?

Not necessarily — sharding is the answer specifically to write throughput or total data volume outgrowing what a single primary can handle. Read-heavy traffic with modest writes and data size is usually better addressed with more secondaries and secondaryPreferred reads (Week 7), which is far simpler to operate than an irreversible shard-key decision.