WiredTiger cache basics
- Default cache: about 50% of (RAM − 1 GB). The OS file cache uses much of the rest.
- When the cache is full of dirty data, application threads help with eviction, raising latency.
const c = db.serverStatus().wiredTiger.cache;
({
maxGB: c["maximum bytes configured"] / 1e9,
inCacheGB: c["bytes currently in the cache"] / 1e9,
dirtyGB: c["tracked dirty bytes in the cache"] / 1e9,
readIntoCache: c["pages read into cache"],
appThreadEvictions: c["pages evicted by application threads"]
})
| Signal | Meaning |
|---|---|
| Cache near max and pages read into cache rising fast | Working set exceeds cache |
| Application-thread evictions increasing | Eviction pressure, latency spikes |
| Dirty bytes high (well above ~5% of cache) | Writes outpacing checkpoints/eviction |
Index sizes and usage
db.orders.stats().indexSizes // bytes per index
db.orders.aggregate([{ $indexStats: {} }]) // accesses.ops since restart
- Indexes should fit in RAM along with hot documents.
- Indexes with
accesses.ops: 0over a full cycle are candidates to hide then drop:
db.orders.hideIndex("status_1") // test impact
db.orders.dropIndex("status_1") // when safe
Better compound indexes (ESR)
Equality fields first, then Sort, then Range:
// query: { customerId: X, createdAt: { $gte: d } } sort { createdAt: -1 }
db.orders.createIndex({ customerId: 1, createdAt: -1 })
Check plans with explain("executionStats"): totalKeysExamined and totalDocsExamined should be close to nReturned (see the slow queries post).
Reduce document and working set size
- Project only needed fields.
- Avoid unbounded arrays inside documents.
- Archive old data (Atlas Online Archive or TTL indexes for expiring data).
- Use compression settings (snappy default, zstd for better ratio at some CPU cost).
When to scale
| Situation | Option |
|---|---|
| Working set slightly larger than cache | Bigger instance (more RAM) |
| Data and writes keep growing beyond one replica set | Sharding with a good shard key |
| Read-heavy analytics | Secondary reads with care or analytics nodes (Atlas) |
Tip
Track cache "pages read into cache" per second alongside query latency. A steady climb is the early warning that the working set is outgrowing memory, weeks before users notice.
Checklist
- Cache usage, dirty ratio and app-thread eviction tracked
- Index sizes and usage reviewed
- Unused indexes hidden then dropped
- Compound indexes follow ESR
- Data size reduced via projection, TTL, archive
- Scaling path decided before cache is exhausted