Introduction
Running MongoDB in production requires understanding its operational capabilities. MongoDB provides robust features for high availability, horizontal scaling, and data protection. This guide covers the essential operational aspects: replica sets for redundancy, sharding for horizontal scalability, backup strategies, security configuration, and monitoring practices.
Whether you are deploying a single development instance or managing a large production cluster, these operational practices will help ensure your MongoDB deployment is reliable, secure, and performant.
Replica Sets
Replica sets provide high availability by maintaining multiple copies of your data across different servers. If the primary node fails, an automatic election promotes a secondary to primary, ensuring continuous operation.
Understanding Replica Set Architecture
A replica set consists of multiple MongoDB instances:
- Primary - Handles all write operations
- Secondary - Replicates data from primary, serves reads
- Arbiter - Participates in elections without storing data
// Replica set configuration
{
_id: 'rs0',
members: [
{ _id: 0, host: 'mongodb1.example.com:27017', priority: 2 },
{ _id: 1, host: 'mongodb2.example.com:27017', priority: 1 },
{ _id: 2, host: 'mongodb3.example.com:27017', priority: 1 }
]
}
Setting Up a Replica Set
# Initialize replica set on primary
mongosh --eval '
rs.initiate({
_id: "rs0",
members: [
{ host: "mongodb1.example.com:27017" },
{ host: "mongodb2.example.com:27017" },
{ host: "mongodb3.example.com:27017" }
]
})
'
# Check replica set status
rs.status()
# Add a member
rs.add("mongodb4.example.com:27017")
# Remove a member
rs.remove("mongodb3.example.com:27017")
Read and Write Concerns
Configure how reads and writes behave across the replica set.
// Strong consistency (default) - reads from primary
db.products.find().readPref('primary')
// Read from nearest replica
db.products.find().readPref('nearest')
// Read from secondaries with latency threshold
db.products.find().readPref('secondaryPreferred', [{ maxStalenessSeconds: 90 }])
// Acknowledged writes (default)
db.products.insertOne({ name: 'Product' }, { writeConcern: { w: 'majority' } })
// Journaled writes
db.products.insertOne({ name: 'Product' }, { writeConcern: { j: true, wtimeout: 5000 } })
Failover Handling
Configure automatic failover and connection handling.
// Connection string with replica set
const uri = 'mongodb://mongodb1.example.com:27017,mongodb2.example.com:27017,mongodb3.example.com:27017/?replicaSet=rs0';
const client = new MongoClient(uri, {
// Retry writes on transient failures
retryWrites: true,
// Retry reads on network errors
retryReads: true,
// Connect timeout
serverSelectionTimeoutMS: 30000
});
Sharding
Sharding enables horizontal scaling by distributing data across multiple servers.
Sharding Concepts
- Shard - A subset of the data, typically a replica set
- Config Servers - Metadata about the cluster
- Mongos - Query router that routes queries to appropriate shards
Setting Up a Sharded Cluster
# Start config server
mongod --configsvr --replSet configReplSet --dbpath /data/config --port 27019
# Start shard servers
mongod --shardsvr --replSet shardReplSet1 --dbpath /data/shard1 --port 27018
mongod --shardsvr --replSet shardReplSet2 --dbpath /data/shard2 --port 27018
# Start mongos (query router)
mongos --configdb configReplSet/config1.example.com:27019,config2.example.com:27019 --port 27017
Shard Keys
Choose shard keys carefully, as they cannot be changed after collection sharding.
// Enable sharding on database
sh.enableSharding("myapp")
// Shard collection with hashed shard key (good for sequential writes)
sh.shardCollection("myapp.orders", { _id: "hashed" })
// Shard collection with compound key (good for range queries)
sh.shardCollection("myapp.products", { category: 1, sku: 1 })
// Shard collection with region-based key
sh.shardCollection("myapp.users", { country: 1, user_id: 1 })
Managing Chunks
# Check chunk distribution
sh.status()
# Split chunk at median
sh.splitAt("myapp.products", { category: "Electronics" })
# Move chunk to specific shard
sh.moveChunk("myapp.products", { category: "Electronics" }, "shard0001")
Backup and Restore
Protecting your data requires regular backups and tested restore procedures.
###mongodump and mongorestore
# Create backup of entire database
mongodump --uri="mongodb://user:password@localhost:27017/mydb" --out=/backups/$(date +%Y%m%d)
# Backup with query filter
mongodump --uri="mongodb://user:password@localhost:27017/mydb" \
--collection=orders \
--query='{"created_at": {"$gte": {"$date": "2026-01-01T00:00:00Z"}}}' \
--out=/backups/orders_2026
# Restore from backup
mongorestore --uri="mongodb://user:password@localhost:27017/mydb" /backups/20260311/mydb
# Restore specific collection
mongorestore --uri="mongodb://user:password@localhost:27017/mydb" \
--collection=orders \
/backups/orders_2026/mydb/orders.bson
Atlas Backup
If using MongoDB Atlas, enable cloud backups.
// Configure Atlas backup (via Atlas UI or CLI)
// - Continuous backups with point-in-time recovery
// - Snapshots (daily, weekly, monthly)
// - Cloud provider snapshots
Point-in-Time Recovery
// Using oplog for point-in-time recovery
// 1. Get timestamp from oplog
db.oplog.rs.find().sort({ ts: -1 }).limit(1)
// 2. Restore to specific time
mongorestore --uri="mongodb://user:password@localhost:27017/mydb" \
--oplogReplay \
--oplogLimit="2026-03-11T10:30:00" \
/backups/full_backup
Security
MongoDB provides comprehensive security features including authentication, authorization, and encryption.
Authentication
Enable and configure authentication.
// Create user administrator
use admin
db.createUser({
user: 'adminUser',
pwd: 'securePassword',
roles: [
{ role: 'userAdminAnyDatabase', db: 'admin' },
{ role: 'readWriteAnyDatabase', db: 'admin' }
]
})
// Enable authentication in mongod.conf
// security:
// authorization: enabled
// keyFile: /etc/mongodb/keyfile
// Create application user
use myapp
db.createUser({
user: 'appUser',
pwd: 'appPassword',
roles: [
{ role: 'readWrite', db: 'myapp' },
{ role: 'read', db: 'reporting' }
]
})
// Authenticate in mongosh
db.auth('appUser', 'appPassword')
// Connection with authentication
const uri = 'mongodb://appUser:appPassword@localhost:27017/myapp';
Role-Based Access Control
Create custom roles for fine-grained permissions.
// Create custom role with specific privileges
db.adminCommand({
createRole: 'dataAnalyst',
privileges: [
{
resource: { db: 'myapp', collection: 'orders' },
actions: ['find', 'aggregate']
},
{
resource: { db: 'myapp', collection: 'products' },
actions: ['find']
}
],
roles: []
})
// Assign role to user
db.grantRolesToUser('analystUser', ['dataAnalyst'])
// List user's roles
db.getUser('analystUser')
Encryption
Enable encryption at rest and in transit.
# mongod.conf for encryption
security:
enableEncryption: true
encryptionKeyFile: /etc/mongodb/encryption.key
# TLS/SSL configuration
net:
tls:
mode: requireTLS
certificateKeyFile: /etc/mongodb/server.pem
CAFile: /etc/mongodb/ca.pem
Network Security
Limit network exposure.
# Bind to specific IP
net:
bindIp: "127.0.0.1,10.0.0.1"
# Enable firewall
sudo ufw allow from 10.0.0.0/24 to any port 27017
Monitoring
Effective monitoring helps identify issues before they impact users.
MongoDB Logs
# View recent logs
tail -f /var/log/mongodb/mongod.log
# Analyze slow queries
grep "slow query" /var/log/mongodb/mongod.log
# Check for errors
grep -i error /var/log/mongodb/mongod.log | tail -50
Database Profiler
Enable profiling to track slow operations.
// Enable profiler
db.setProfilingLevel(1, { slowms: 100 }) // Log operations > 100ms
// Query profiler data
db.system.profile.find({ millis: { $gt: 1000 } }).sort({ ts: -1 }).limit(10)
// Disable profiler
db.setProfilingLevel(0)
Atlas Monitoring
If using Atlas, leverage built-in monitoring.
// Monitor via Atlas APIs
// - Connection counts
// - Query performance
// - Memory usage
// - Disk I/O
// - Replication lag
Custom Metrics
// Get server status
db.serverStatus()
// Get collection stats
db.products.stats()
// Get index stats
db.products.getIndexes()
// Check replication lag
rs.printSlaveReplicationInfo()
Performance Tuning
Optimize MongoDB for your workload.
Memory Configuration
// WiredTiger cache configuration
// Target: (RAM - 1GB) / 2
// In mongod.conf:
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 8
Connection Pooling
Configure appropriate connection pool sizes.
const client = new MongoClient(uri, {
maxPoolSize: 10, // Maximum connections
minPoolSize: 2, // Minimum connections
maxIdleTimeMS: 30000, // Connection timeout
waitQueueTimeoutMS: 3000 // Queue timeout
});
Query Optimization
// Use projection to limit fields returned
db.products.find({ category: 'Electronics' }, { name: 1, price: 1 })
// Use limit for pagination
db.products.find({ category: 'Electronics' }).limit(20).skip(40)
// Use explain to analyze queries
db.products.find({ category: 'Electronics', price: { $lt: 100 } })
.sort({ price: 1 })
.explain('executionStats')
Maintenance
Regular maintenance keeps your deployment healthy.
Compact Collections
// Compact collection (reclaims disk space)
db.runCommand({ compact: 'products' })
// Compact with force (allows on single shard)
db.runCommand({ compact: 'products', force: true })
Repair Databases
// Repair database (after unclean shutdown)
db.repairDatabase()
Index Maintenance
// Rebuild indexes
db.products.reIndex()
// Drop unused indexes
db.products.dropIndex('unnecessary_index_name')
Deployment Options
Choose the right deployment model for your needs.
Self-Managed
# Docker Compose for development
version: '3.8'
services:
mongodb:
image: mongo:8.0
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
Atlas Serverless
// Create serverless instance via Atlas API
// Pay only for resources consumed
// Ideal for variable workloads
Atlas Dedicated
// Dedicated cluster with
// - Multi-region deployment
// - Sharding
// - Advanced security
// - Managed backups
Disaster Recovery
Prepare for worst-case scenarios.
Offsite Backups
# Backup to cloud storage
mongodump --uri="mongodb://admin:pass@localhost:27017" \
--archive="/s3/bucket/mongodb-backup.gz" \
--gzip
Runbook Template
Create runbooks for common scenarios.
## Database Failover Runbook
1. Check replica set status
rs.status()
2. Identify failed node
- Note: If primary fails, election will occur automatically
3. For manual failover:
rs.stepDown()
4. Verify new primary elected
rs.status().members.filter(m => m.stateStr === 'PRIMARY')
5. Address failed node
- Check logs
- Fix issue
- Restart or replace
External Resources
Conclusion
MongoDB operations require careful attention to high availability, scaling, security, and monitoring. This guide covered the essential operational practices: replica sets for redundancy, sharding for horizontal scalability, backup strategies, security configuration, and monitoring approaches.
By following these operational best practices, you can ensure your MongoDB deployment is reliable, secure, and performant. Regular maintenance, monitoring, and testing of backup procedures are essential for production environments.
In the next article, we will explore MongoDB’s internal architecture, understanding how the WiredTiger storage engine works and how MongoDB handles data internally.
Comments