Skip to main content

MongoDB Production Readiness

Introduction

When moving your MongoDB database from development to production, there are several critical considerations to ensure your application runs efficiently, securely, and reliably. Production readiness involves proper configuration, security measures, performance optimization, and operational practices that help prevent downtime and data loss.

This guide will walk you through the essential steps to make your MongoDB deployment production-ready, covering everything from server configuration to monitoring and maintenance strategies.

Prerequisites

Before deploying MongoDB to production, ensure you have:

  • MongoDB 4.4+ installed (latest stable version recommended)
  • Basic understanding of MongoDB concepts
  • Server(s) with sufficient resources for your workload
  • Network infrastructure allowing necessary connectivity

Proper Server Sizing and Configuration

Hardware Requirements

Your hardware needs depend on your workload, but here are general guidelines:

  • CPU: 2+ cores for most workloads, 8+ cores for high-traffic applications
  • RAM: At least 8GB, with enough to hold your working set
  • Disk: SSD strongly recommended for production; NVMe for high-performance needs
  • Network: 1 Gbps minimum, 10 Gbps preferred for replica sets

Operating System Configuration

bash
# Disable transparent huge pages (Linux)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

# Increase file descriptor limits in /etc/security/limits.conf
mongodb soft nofile 64000
mongodb hard nofile 64000
mongodb soft nproc 64000
mongodb hard nproc 64000

# Configure swap settings for better performance
vm.swappiness = 1

MongoDB Configuration File

Create a proper mongod.conf file with appropriate settings:

yaml
# MongoDB configuration file
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 2 # Adjust based on available RAM (typically 50% of RAM)

systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true

net:
port: 27017
bindIp: 127.0.0.1 # Change to server IP or 0.0.0.0 if needed with proper security

processManagement:
timeZoneInfo: /usr/share/zoneinfo
fork: true # Run as daemon
pidFilePath: /var/run/mongodb/mongod.pid

security:
authorization: enabled # Enable authentication

Securing Your MongoDB Deployment

Enable Authentication

Always enable authentication in production environments:

js
// Create an admin user
use admin
db.createUser({
user: "adminUser",
pwd: "securePassword123", // Use a strong password
roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
})

// Create an application user with limited permissions
use myApplication
db.createUser({
user: "appUser",
pwd: "anotherSecurePassword456",
roles: [{ role: "readWrite", db: "myApplication" }]
})

When connecting with a client:

js
// Connect with authentication
const { MongoClient } = require('mongodb');

const uri = "mongodb://appUser:anotherSecurePassword456@localhost:27017/myApplication";
const client = new MongoClient(uri);

async function run() {
try {
await client.connect();
console.log("Connected successfully to server");
// Perform operations here
} finally {
await client.close();
}
}
run().catch(console.dir);

Network Security

  1. Configure Firewall Rules:
bash
# Using UFW (Ubuntu)
sudo ufw allow from trusted-ip-address to any port 27017

# Using iptables
sudo iptables -A INPUT -p tcp -s trusted-ip-address --dport 27017 -j ACCEPT
  1. Enable TLS/SSL:

Generate certificates:

bash
openssl req -newkey rsa:2048 -nodes -keyout mongodb.key -x509 -days 365 -out mongodb.crt
cat mongodb.key mongodb.crt > mongodb.pem

Update your MongoDB configuration:

yaml
net:
port: 27017
bindIp: 0.0.0.0
tls:
mode: requireTLS
certificateKeyFile: /path/to/mongodb.pem

Client connection with SSL:

js
const { MongoClient } = require('mongodb');

const uri = "mongodb://appUser:anotherSecurePassword456@localhost:27017/myApplication?tls=true";
const client = new MongoClient(uri, {
tls: true,
tlsCAFile: '/path/to/ca.pem',
tlsAllowInvalidHostnames: false
});

Implementing High Availability

Replica Sets

For production, a minimum 3-node replica set is recommended:

Setup a replica set:

js
// Initialize the replica set
rs.initiate({
_id: "myReplicaSet",
members: [
{ _id: 0, host: "mongodb-server-1:27017" },
{ _id: 1, host: "mongodb-server-2:27017" },
{ _id: 2, host: "mongodb-server-3:27017" }
]
})

// Check replica set status
rs.status()

Connection string for replica set:

mongodb://appUser:password@mongodb-server-1:27017,mongodb-server-2:27017,mongodb-server-3:27017/myApplication?replicaSet=myReplicaSet

Sharding for Scalability

For very large datasets, consider implementing sharding:

js
// Enable sharding for a database
sh.enableSharding("myLargeDatabase")

// Shard a collection based on a key
sh.shardCollection(
"myLargeDatabase.highVolumeCollection",
{ userId: 1 } // Sharding key
)

Performance Optimization

Indexing Strategy

Create proper indexes for your common queries:

js
// Create a simple index
db.products.createIndex({ name: 1 })

// Create a compound index
db.orders.createIndex({ user_id: 1, order_date: -1 })

// Create a text index for text searches
db.articles.createIndex({ content: "text" })

// Create a unique index
db.users.createIndex({ email: 1 }, { unique: true })

Check index usage with explain:

js
db.products.find({ name: "Widget" }).explain("executionStats")

Sample Output:

json
{
"queryPlanner": {
"plannerVersion": 1,
"namespace": "mydb.products",
"indexFilterSet": false,
"parsedQuery": { "name": { "$eq": "Widget" } },
"winningPlan": {
"stage": "FETCH",
"inputStage": {
"stage": "IXSCAN",
"keyPattern": { "name": 1 },
"indexName": "name_1",
"isMultiKey": false,
"direction": "forward",
"indexBounds": { "name": ["[\"Widget\", \"Widget\"]"] }
}
},
"rejectedPlans": []
},
"executionStats": {
"executionSuccess": true,
"nReturned": 5,
"executionTimeMillis": 0,
"totalKeysExamined": 5,
"totalDocsExamined": 5
}
}

Connection Pooling

Set up proper connection pooling in your application:

js
// Node.js MongoDB driver connection with pooling
const { MongoClient } = require('mongodb');

const uri = "mongodb://appUser:password@mongodb-server-1:27017,mongodb-server-2:27017/myApplication?replicaSet=myReplicaSet";
const client = new MongoClient(uri, {
maxPoolSize: 50, // Maximum number of connections in the pool
minPoolSize: 5, // Minimum number of connections to maintain
maxIdleTimeMS: 30000, // How long a connection can remain idle before being closed
waitQueueTimeoutMS: 10000 // How long to wait for a connection to become available
});

Backup and Disaster Recovery

Regular Backups

  1. Using mongodump:
bash
# Backup an entire database
mongodump --uri="mongodb://username:password@localhost:27017/mydb" --out=/backup/$(date +%Y-%m-%d)

# Backup a specific collection
mongodump --uri="mongodb://username:password@localhost:27017/mydb" --collection=users --out=/backup/$(date +%Y-%m-%d)
  1. Restore with mongorestore:
bash
# Restore an entire backup
mongorestore --uri="mongodb://username:password@localhost:27017" /backup/2023-06-15/

# Restore a specific collection
mongorestore --uri="mongodb://username:password@localhost:27017" --nsInclude="mydb.users" /backup/2023-06-15/

Point-in-Time Recovery

Enable oplog for point-in-time recovery capabilities:

yaml
# In mongod.conf for replica sets
replication:
replSetName: myReplicaSet
oplogSizeMB: 10240 # Adjust size based on write volume

Monitoring and Alerting

Key Metrics to Monitor

  1. Resource Metrics:

    • CPU usage
    • Memory usage
    • Disk I/O and space
    • Network traffic
  2. MongoDB-specific Metrics:

    • Query performance
    • Connections
    • Replication lag
    • Operation counters

MongoDB Monitoring Tools

  1. MongoDB Compass for visual exploration of data and performance
  2. MongoDB Atlas if using the cloud service
  3. Prometheus with MongoDB Exporter for metrics collection

Sample Prometheus configuration:

yaml
# prometheus.yml
scrape_configs:
- job_name: 'mongodb'
static_configs:
- targets: ['mongodb-exporter:9216']
  1. Grafana Dashboard for visualization:
bash
# Run Grafana with Docker
docker run -d -p 3000:3000 grafana/grafana

Database Profiling

Enable database profiling for slow queries:

js
// Set profiling level (0=off, 1=slow queries, 2=all queries)
db.setProfilingLevel(1, { slowms: 100 })

// Check profiling status
db.getProfilingStatus()

// Query the profiler data
db.system.profile.find().sort({ ts: -1 }).limit(10)

Production Deployment Checklist

Pre-Deployment Checklist

  • ✅ Authentication and authorization configured
  • ✅ Network security measures in place (firewall, TLS)
  • ✅ Replica set configured for high availability
  • ✅ Proper indexes created for common queries
  • ✅ Connection pooling configured in application
  • ✅ Storage capacity planned with room for growth
  • ✅ Backup strategy implemented and tested
  • ✅ Monitoring solution configured
  • ✅ Resource limits set appropriately

Post-Deployment Monitoring

  • ✅ Regular review of slow queries
  • ✅ Index usage analysis
  • ✅ Storage growth monitoring
  • ✅ Regular backup verification
  • ✅ Performance benchmarking

Practical Example: E-commerce Application

Let's consider a practical example of setting up MongoDB for an e-commerce application:

Data Model

js
// Products collection
db.products.insertOne({
name: "Smartphone X",
price: 699.99,
description: "Latest smartphone with amazing camera",
category: "electronics",
stock: 120,
tags: ["phone", "camera", "5G"]
})

// Orders collection
db.orders.insertOne({
user_id: ObjectId("60d5ec6ac3e5e82e610d5e7a"),
order_date: new Date(),
status: "processing",
shipping: {
address: "123 Main St",
city: "Anytown",
zip: "12345"
},
items: [
{
product_id: ObjectId("60d5ec6ac3e5e82e610d5e7b"),
name: "Smartphone X",
price: 699.99,
quantity: 1
}
],
total: 699.99
})

Indexes for Performance

js
// Create indexes for common queries
db.products.createIndex({ name: "text", description: "text" }) // Text search
db.products.createIndex({ category: 1 }) // Filter by category
db.products.createIndex({ price: 1 }) // Sort by price
db.orders.createIndex({ user_id: 1 }) // Find user orders
db.orders.createIndex({ order_date: -1 }) // Recent orders first
db.orders.createIndex({ "items.product_id": 1 }) // Find orders containing product

Sample Queries

js
// Find products with text search
db.products.find({ $text: { $search: "smartphone camera" } })

// Get recent orders for a user
db.orders.find({
user_id: ObjectId("60d5ec6ac3e5e82e610d5e7a")
}).sort({ order_date: -1 }).limit(10)

// Aggregate sales by category
db.orders.aggregate([
{ $unwind: "$items" },
{ $lookup: {
from: "products",
localField: "items.product_id",
foreignField: "_id",
as: "product_info"
}},
{ $unwind: "$product_info" },
{ $group: {
_id: "$product_info.category",
totalSales: { $sum: { $multiply: ["$items.price", "$items.quantity"] } }
}},
{ $sort: { totalSales: -1 } }
])

Connection String for Application

js
// Node.js production application connection
const { MongoClient } = require('mongodb');

const uri = "mongodb://appUser:password@mongodb-server-1:27017,mongodb-server-2:27017,mongodb-server-3:27017/ecommerce?replicaSet=myReplicaSet&retryWrites=true&w=majority";

const client = new MongoClient(uri, {
maxPoolSize: 50,
connectTimeoutMS: 5000,
socketTimeoutMS: 45000,
tls: true
});

async function run() {
try {
await client.connect();
console.log("Connected successfully to MongoDB");

const db = client.db("ecommerce");
const productsCollection = db.collection("products");
const ordersCollection = db.collection("orders");

// Application logic here

} catch (err) {
console.error("Database connection error:", err);
}
}

run();

Summary

Preparing MongoDB for production requires careful attention to:

  1. Security - Authentication, access control, and encryption
  2. Performance - Proper indexing, connection pooling, and resource allocation
  3. Availability - Replica sets and proper failover configuration
  4. Monitoring - Tracking critical metrics and setting up alerts
  5. Backup and Recovery - Regular backups and tested recovery procedures

Following these best practices will help ensure your MongoDB deployment is reliable, secure, and performant in production environments. Remember that production readiness is an ongoing process that requires regular maintenance and optimization as your application evolves.

Additional Resources

Practice Exercises

  1. Create a replica set on your development environment with three nodes and test failover scenarios
  2. Design an indexing strategy for a sample application and benchmark query performance
  3. Set up a monitoring solution using Prometheus and Grafana for your MongoDB deployment
  4. Create a backup and recovery strategy including automated backups and restoration testing
  5. Implement security best practices including authentication, authorization, and encryption


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)