Diagnosing PM2 Cluster Mode Misbehavior: An Engineering Decision Guide
A hands‑on diagnostic guide to troubleshoot PM2 cluster mode misbehaviors like uneven load, memory restarts, and CPU imbalance. Follow step‑by‑step checks, fixes, and escalation paths to keep Node.js apps running smoothly.
03 Apr 2026, 16:47 UTC

Recognizing the Problem
When a Node.js application is run under PM2 in cluster mode, you may notice one or more of the following symptoms:
- Uneven request distribution – some workers handle far more traffic than others.
- Frequent worker crashes or restarts triggered by
max_memory_restart. - CPU under‑utilization or a single worker hogging all CPU cycles.
- Workers stuck in a
stalledstate, event loop blocked by synchronous code. - Cluster mode appears disabled even though you configured it.
These issues often stem from misconfigurations, environment constraints, or application code patterns that conflict with PM2’s clustering model.
Diagnostic Table
| Symptom | Possible Cause | Primary Diagnostic Check |
|---|---|---|
| Uneven traffic | Sticky sessions or load‑balancer mis‑config | Verify load‑balancer algorithm |
| Frequent restarts | Memory leak or low max_memory_restart | Check PM2 logs for memory warnings |
| CPU imbalance | Single worker handling all requests | Inspect pm2 monit CPU per worker |
| Stalled workers | Blocking synchronous code | Search logs for event loop lag warnings |
| Cluster disabled | --no-cluster flag or env override | Review ecosystem file and env vars |
Step‑by‑Step Checks
- Confirm Cluster Mode is Enabled
pm2 show <app-name>Look for
mode: clusterin the output. If it showsmode: fork, cluster is disabled. - Validate Instances Setting
pm2 ecosystemOpen
ecosystem.config.jsand ensureinstances: 'max'or a numeric value is set. The default is 1, which disables clustering. - Inspect Load Balancer Configuration
- If you are using an external LB (NGINX, HAProxy, AWS ELB), check that it uses round‑robin or consistent hashing rather than sticky sessions.
- In the application, ensure no session‑affinity middleware forces requests to the same worker.
- Monitor CPU and Memory per Worker
pm2 monitVerify that each worker shows similar CPU usage. If one worker dominates, it may be handling all traffic.
- Check for Memory‑Restart Events
pm2 logs <app-name> | grep "max_memory_restart"Frequent entries indicate the threshold is too low or the app leaks memory.
- Detect Event Loop Lag
pm2 logs <app-name> | grep "event loop lag"Large lag values point to blocking synchronous operations.
- Validate Environment Flags
echo $NODE_OPTIONSEnsure
--no-clusteris not set inadvertently.
Fixes Tied to Findings
- Uneven Traffic
- Reconfigure the load balancer to use round‑robin or consistent hashing.
- Remove sticky‑session middleware or set
app.set('trust proxy', 1)and useexpress-sessionwith a shared store.
- Frequent Restarts
- Increase
max_memory_restartinecosystem.config.js:module.exports = { apps: [{ name: 'myapp', script: 'server.js', instances: 'max', max_memory_restart: '1G', env: { NODE_ENV: 'production' } }] }; - Profile the application with
clinic.jsornode --inspectto locate memory leaks.
- Increase
- CPU Imbalance
- If a single worker is hogging CPU, verify that the worker count matches the number of CPU cores:
instances: 'max'will spawnos.cpus().lengthworkers. - Check for heavy synchronous code in request handlers. Refactor to async/await or offload to worker threads.
- If a single worker is hogging CPU, verify that the worker count matches the number of CPU cores:
- Stalled Workers
- Search the codebase for long synchronous loops,
fs.readFileSync, or blocking crypto calls. - Replace with async equivalents or move heavy tasks to
worker_threadsor a dedicated microservice.
- Search the codebase for long synchronous loops,
- Cluster Disabled
- Remove
--no-clusterfromnode_argsorNODE_OPTIONS. - Set
cluster: truein the ecosystem file if you use thepm2 startcommand with the--clusterflag.
- Remove
Escalation Criteria
If after applying the above fixes the problem persists, consider the following:
- Run a controlled load test (e.g.,
wrk -t12 -c400 -d30s http://localhost:3000/) and capture worker request counts withpm2 logrotateor custom instrumentation. - Review Node.js version compatibility – cluster mode is stable on Node 12+, but older releases may have IPC bugs.
- Examine shared global state: if workers modify shared objects, race conditions can cause erratic behavior. Migrate to a Redis or database store.
- If the application uses native addons, ensure they are thread‑safe and compiled for the target architecture.
- Contact PM2 support or file an issue on the PM2 GitHub repository with detailed logs and environment info.
Practical Verification Checklist
- Run
pm2 list– all instances should showonlinestatus. - Confirm
pm2 show <app>displaysmode: clusterand the correct number of instances. - Use
pm2 monitto see balanced CPU/memory across workers. - Check logs for absence of
max_memory_restartorevent loop lagentries after load test. - If using a load balancer, run a traffic distribution test (e.g.,
ab -n 10000 -c 100 http://lb/) and confirm even request counts per backend IP.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.