How MongoDB Data Balancing Works and How to Configure It Using Docker Compose
MongoDB's balancer is a background process that runs on the mongos router to automatically migrate chunks between shards, ensuring even data distribution, and you can configure it via the config.settings collection or helper methods like sh.startBalancer() and sh.setChunkSize().
MongoDB uses a sharded cluster architecture to distribute data across multiple replica sets, relying on an automated data balancing mechanism to maintain performance as datasets grow. This guide explains how the balancer manages chunk migrations and how to configure it using the minhhungit/mongodb-cluster-docker-compose repository, which provides a complete Docker Compose setup for running a sharded MongoDB cluster locally.
What Is the MongoDB Balancer and How It Works
The balancer is responsible for maintaining equilibrium across a sharded cluster by moving chunks—contiguous ranges of shard key values—from shards with more data to those with less.
Chunk-Based Data Distribution
MongoDB partitions data into chunks based on the shard key. When a chunk grows beyond the chunkSize threshold (default 64 MiB), the config server marks it for splitting. The balancer then evaluates the distribution across all shards and initiates migrations if it detects an imbalance.
The Balancer Process on Mongos
According to the repository's README, the balancer runs as a background process on the mongos router. The sample sh.status() output shows:
balancer:
Currently enabled: yes
Currently running: no
No recent migrations
This indicates the balancer is enabled by default but idle when the cluster is balanced. The status output is documented in the README around lines 171‑174 of readme.md.
Core Components of the Sharded Cluster
The data balancing mechanism relies on three architectural components defined in the repository's docker-compose.yml and startup scripts.
Config Servers Store Metadata
The config servers maintain the cluster's metadata, including chunk ranges and balancer settings. In docker-compose.yml, three config-server containers (e.g., mongo-config-01) are defined to provide redundancy for this critical metadata.
Mongos Router Runs the Balancer
The mongos process acts as the query router and hosts the balancer logic. The scripts/entrypoint-route.sh script starts the mongos instance and waits for config servers and shards to become available before executing sh.addShard() commands to register shards with the cluster.
Shard Replica Sets Hold Data
Data is stored in shard replica sets. Each shard is started by an entrypoint-shardXX.sh script (e.g., scripts/entrypoint-shard01.sh) that initiates the replica set via the init_shard() function before joining the cluster.
How to Check Balancer Status
To inspect the current balancing state in the Docker environment, execute mongosh on the router container:
docker exec -it router-01 mongosh --port 27017 <<'EOF'
sh.status()
EOF
Look for the balancer: section in the output. It reports whether the balancer is enabled, whether it is actively running, and statistics on recent chunk migrations.
Configuring the Data Balancing Mechanism
MongoDB exposes balancer controls through the config.settings collection in the admin database. All configuration commands must run against the mongos router.
Enable or Disable the Balancer
Use the helper methods to toggle the balancer state:
// Disable automatic balancing
sh.stopBalancer();
// Re-enable automatic balancing
sh.startBalancer();
These commands update the balancerEnabled field in config.settings. Verify the change with:
db.getSiblingDB("config").settings.find({_id: "balancer"}).pretty();
Adjust Chunk Size
The default chunkSize is 64 MiB. Increase or decrease it to control the granularity of data distribution:
// Set chunk size to 128 MiB
sh.setChunkSize(128);
Smaller chunks enable more even distribution but increase metadata overhead on config servers. Larger chunks reduce migration frequency but may create hot spots on individual shards.
Set a Balancing Window
Restrict balancing operations to off-peak hours by defining an activeWindow:
db.getSiblingDB("config").settings.update(
{ _id: "balancer" },
{ $set: {
activeWindow: { start: "03:00", stop: "05:00" } // 3 am-5 am UTC
} },
{ upsert: true }
);
During hours outside this window, the balancer will not initiate new chunk migrations.
Force Manual Balancing
To trigger an immediate balancing round without waiting for the background process:
sh.startBalancer();
sh.balance(); // Forces an immediate balancing round
Disable Auto-Splitting
For testing or specific maintenance scenarios, prevent automatic chunk splitting:
db.getSiblingDB("config").settings.update(
{ _id: "autosplit" },
{ $set: { enabled: false } },
{ upsert: true }
);
Complete Configuration Example
Below is a self-contained script you can execute inside the router-01 container to tune the balancer for a production-like environment. Save this as scripts/balance-config.sh in your repository:
#!/bin/bash
# router-balancer-config.sh – run inside router-01
mongosh --port 27017 <<'EOS'
print("Current balancer status:");
sh.status().balancer
// Enable the balancer (if it was disabled)
sh.startBalancer();
// Set chunk size to 128 MiB (default is 64 MiB)
sh.setChunkSize(128);
// Restrict balancing to a nightly window (02:00-04:00 UTC)
db.getSiblingDB("config").settings.update(
{ _id: "balancer" },
{ $set: { activeWindow: { start: "02:00", stop: "04:00" } } },
{ upsert: true }
);
print("Updated balancer configuration:");
db.getSiblingDB("config").settings.find({_id:"balancer"}).pretty();
EOS
Invoke the script after the cluster has started:
docker exec -it router-01 bash /scripts/balance-config.sh
Where to Find the Relevant Code in the Repository
The minhhungit/mongodb-cluster-docker-compose repository implements the sharded cluster architecture that supports the data balancing mechanism described above.
| File | Purpose |
|---|---|
docker-compose.yml |
Declares the router, config servers, and shard containers that make up the cluster. |
scripts/entrypoint-route.sh |
Starts mongos, waits for config servers and shards, then executes sh.addShard() commands. |
scripts/entrypoint-shard01.sh |
Boots the first shard's mongod instance and initiates the replica set via the init_shard() function. |
readme.md |
Contains sample sh.status() output showing the balancer block and cluster verification steps. |
scripts/init-router.js |
Holds the JavaScript commands that register shards with the cluster metadata. |
Browse these files directly on GitHub:
- Router entrypoint: https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/scripts/entrypoint-route.sh
- Shard entrypoint: https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/scripts/entrypoint-shard01.sh
- Full README: https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/readme.md
Summary
- The MongoDB balancer is a background process running on the
mongosrouter that migrates chunks (ranges of shard key values) between shards to maintain even data distribution. - Configuration is managed through the
config.settingscollection using helpers likesh.startBalancer(),sh.stopBalancer(), andsh.setChunkSize(), or by setting anactiveWindowfor time-based restrictions. - The minhhungit/mongodb-cluster-docker-compose repository provides the Docker infrastructure—defined in
docker-compose.ymland managed byentrypoint-route.sh—that implements the config servers, mongos router, and shard replica sets required for automatic balancing. - You can inspect balancer status with
sh.status(), force immediate balancing withsh.balance(), and tune performance by adjusting the chunkSize default of 64 MiB.
Frequently Asked Questions
How do I know if the MongoDB balancer is actually running?
Connect to the mongos router and run sh.status(). The output includes a balancer: section that reports Currently enabled and Currently running status. In the minhhungit/mongodb-cluster-docker-compose repository, the README shows sample output indicating the balancer is enabled by default but may display Currently running: no when the cluster is already balanced or when no migrations are needed.
What is the default chunk size, and when should I change it?
The default chunkSize is 64 MiB. You should increase it (using sh.setChunkSize()) if you have a very large dataset and want to reduce the overhead of frequent migrations and metadata tracking. Decrease it if you need finer-grained distribution to avoid hot spots on individual shards, though this increases the storage and processing load on the config servers.
Can I schedule MongoDB balancing to run only during off-peak hours?
Yes. You can define an activeWindow in the config.settings collection to restrict the balancer to specific UTC times. For example, setting activeWindow: { start: "02:00", stop: "04:00" } ensures the balancer only migrates chunks between 2 am and 4 am UTC, preventing balancing operations from impacting peak-hour workloads.
Where is the balancer process located in the Docker Compose architecture?
In the minhhungit/mongodb-cluster-docker-compose setup, the balancer runs as part of the mongos router process defined in docker-compose.yml and started by scripts/entrypoint-route.sh. You must connect to the router container (e.g., router-01) to inspect or configure balancer settings, as the shard containers only run mongod instances and do not execute balancing logic.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →