Files
clean-architecture-backend-…/docs/mongodb/advanced/sharding.md
T
DongHyeonkaandClaude Opus 5 d57d2f62a0 feat(mongodb): implement the MongoDB document persistence platform
Implements the mongodb-superpowers-package design: Stable Tasks 1-50 and
Advanced Tasks 1-15.

The design assumes 19 Stable + 12 Advanced Gradle projects under
modules/mongodb*. This repository's fail-closed registry declares exactly 19
leaf identities, so those modules become package boundaries inside the
registered leaf :adapter:outbound:persistence-mongo, with the design's module
dependency table enforced by ten ArchUnit rules. The mapping and every
deviation are recorded in docs/mongodb/repository-adaptation.md.

Contract highlights, all enforced by tests rather than convention:

- Transaction body retry and commit retry are separate loops. A new session per
  body attempt; commit-only retry on an unknown commit. The body is never
  replayed after a commit ambiguity, so a failover cannot become a duplicate.
- MongoExecutionOutcome keeps both ambiguous outcomes distinct from success and
  failure, and MongoFailureContext records only the design-permitted fields.
- Failure classification reads server error labels before numeric codes.
- BSON representations come from a pinned manifest, never a library default,
  and a golden type-signature gate fails on any drift.
- Index and validator changes go through the manifest and the admin plane;
  metadata ownership gates every drop.
- Every Advanced capability refuses construction unless its flag is enabled.

Verified against real servers, not only unit tests. Running the lanes for the
first time exposed four defects that a green `check` had hidden:

- Four release lanes passed while executing zero tests; the gate now counts
  executed tests per lane and fails on zero.
- The "single replica set" fixture was a standalone, because Testcontainers 2.x
  needs withReplicaSet(); its test only asserted a connection string.
- The three-node fixture was three independent clusters, so no election could
  occur, and awaitNewPrimary() compared against the post-stop primary.
- The migration lease checked modifiedCount, so a same-millisecond refresh read
  as a lost lease.

scripts/verify-mongodb-platform.sh now reports:
  9 lanes, 0 skipped, 0 failed, every evidence category produced.

scripts/verify-mongodb-advanced.sh reports NOT PROMOTABLE: actual-topology
evidence (real sharded cluster, real KMS, real target deployment) is
unobtainable here, so it is named rather than assumed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 13:41:00 +09:00

4.0 KiB

Advanced — Sharding

Capability: MongoCapability.SHARDING Property: ca-skeleton.persistence-mongo.advanced.sharding.enabled Status: Advanced. Reshard orchestration remains Experimental.

Requirements

Topology A real sharded cluster. A replica set cannot exercise routing.
Server MongoDB 7.0 or 8.0.
Privilege MongoPrincipalRole.SHARD_ADMIN for the admin plane; the application role is unchanged.
Gate mongoShardedTest lane with MongoShardingContractSuite.

Shard key

ShardKeyDescriptor declares the key as an ordered list of ShardKeyPart plus a ShardStrategy:

Strategy Distributes Cost
RANGE by value ranges Range queries stay targeted; a monotonic key (a timestamp, an ObjectId) sends every insert to one shard.
HASHED by hash of the key Inserts spread evenly; every range query becomes scatter-gather.

There is no strategy that is good at both, which is why the choice is a declaration rather than a default.

Routing classification

ShardAwareQueryValidator classifies each query before execution:

MongoRoutingClassification Meaning
TARGETED The full shard key is present. One shard answers.
PREFIX_TARGETED A prefix of a compound key is present. A subset of shards answers.
SCATTER_GATHER No shard-key predicate. Every shard answers.
REJECTED Scatter-gather where the profile forbids it.

A scatter-gather query is not an error — some queries legitimately need every shard — but it must be declared. Undeclared scatter-gather raises MongoShardRoutingException. The reason is that scatter-gather passes every test on a single-shard development cluster and only degrades once the cluster grows, at which point the query is already in production and the fix is a schema change.

Unsupported combinations

  • Unique index on a field that is not a prefix of the shard key. MongoDB cannot enforce it across shards, and it fails at index creation, not at query time.
  • Transactions that touch documents on multiple shards remain supported but cost a cross-shard two-phase commit. Prefer a shard key that keeps a transaction's documents co-located.
  • CSFLE on a sharded collection: see encryption.md for the combinations that are refused.

Admin plane

MongoShardingAdminGateway (D4, SHARD_ADMIN credential) covers shard-collection, refine-shard-key and reshard.

ShardKeyAnalyzer produces a ShardKeyReadinessReport before sharding a collection: cardinality, frequency skew and monotonicity. A key with low cardinality creates jumbo chunks that cannot be split; a monotonic key creates a hot shard. Both are visible in the report and invisible in a functional test.

ReshardApproval is required for a reshard — a named approver and a stated window. Resharding rewrites the collection: it duplicates the data during the operation and saturates IO. It is not a runtime operation and the type refuses to pretend otherwise.

Failure recovery

Symptom Cause Action
MongoShardRoutingException Undeclared scatter-gather Add the shard key to the predicate, or declare the query as scatter-gather in its profile after review.
Jumbo chunks Low-cardinality shard key Refine the shard key (adds a suffix, non-destructive) before considering a reshard.
One hot shard Monotonic range key Refine with a high-cardinality prefix, or reshard to hashed if range queries are not needed.
Balancer never converges Chunk migration blocked by long-running operations Check for long transactions and cursors; the balancer waits on them.

Promotion evidence

Per ADR-MONGO-ADV-001: actual sharded-cluster evidence, security review of the SHARD_ADMIN role, a migration path for an existing unsharded collection, failure cases (undeclared scatter-gather refused, jumbo chunk detected), and this document as the runbook. Reshard orchestration stays Experimental until operational scale evidence exists.