-
-
Notifications
You must be signed in to change notification settings - Fork 162
PM2 cluster
Application launched with PM2 takes control over IPC. It requires to use PM2 messages bus to send and receive between master and forks. It also requires to configure application as master process is PM2 itself and it can not be used to store limits.
Note: maximum duration for PM2 Cluster limiter is 2147483 seconds or about 24 days because of setTimeout
limitation.
Create app.config.js
module.exports = {
apps: [
{
name: "app-master",
script: "./app-master.js",
instances: 1,
autorestart: true,
}, {
name: "app-worker",
script: "./app-worker.js",
instances: 4,
exec_mode: "cluster",
autorestart: true,
}]
};
One instance of app-master.js
is launched to store limits. It requires pm2
to get access to IPC through it.
// app-master.js
const pm2 = require('pm2');
const { RateLimiterClusterMasterPM2 } = require('rate-limiter-flexible');
new RateLimiterClusterMasterPM2(pm2);
4 instances of app-worker.js
are launched to process requests.
// app-worker.js
const { RateLimiterCluster } = require('rate-limiter-flexible');
const rateLimiter = new RateLimiterCluster({
keyPrefix: 'pm2clusterlimiter', // Must be unique for each limiter
points: 100,
duration: 1,
timeoutMs: 3000 // Promise is rejected, if master doesn't answer for 3 secs
});
rateLimiter.consume(remoteAddress, 2) // consume 2 points
.then((rateLimiterRes) => {
// 2 points consumed
})
.catch((rateLimiterRes) => {
// Not enough points to consume
});
Application is started with command pm2 start app.config.js
.
Endpoint is pure NodeJS endpoint launched in node:10.5.0-jessie
Docker containers with 4 workers and 1 master.
Endpoint is limited by RateLimiterCluster
for 100 random keys with config:
new RateLimiterCluster({
points: 5,
duration: 1,
});
By bombardier -c 1000 -l -d 30s -r 2000 -t 1s http://127.0.0.1:3000
Test with 1000 concurrent requests with maximum 2000 requests per sec during 30 seconds
Reqs/sec 1991.25 496.53 3215.70
Latency 2.35ms 349.22us 8.51ms
Latency Distribution
50% 2.31ms
75% 2.79ms
90% 3.25ms
95% 3.53ms
99% 4.09ms
HTTP codes:
1xx - 0, 2xx - 14489, 3xx - 0, 4xx - 45531, 5xx - 0
Instances state during test
┌────────────────┬────┬─────────┬─────────┬──────┬────────┬─────────┬────────┬─────┬───────────┬────────┬──────────┐
│ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │
├────────────────┼────┼─────────┼─────────┼──────┼────────┼─────────┼────────┼─────┼───────────┼────────┼──────────┤
│ pm2-app-master │ 0 │ 1.0.0 │ fork │ 2923 │ online │ 0 │ 32s │ 35% │ 55.8 MB │ animir │ enabled │
│ pm2-app-worker │ 1 │ 1.0.0 │ cluster │ 2922 │ online │ 0 │ 32s │ 14% │ 47.8 MB │ animir │ enabled │
│ pm2-app-worker │ 2 │ 1.0.0 │ cluster │ 2924 │ online │ 0 │ 32s │ 9% │ 46.6 MB │ animir │ enabled │
│ pm2-app-worker │ 3 │ 1.0.0 │ cluster │ 2925 │ online │ 0 │ 32s │ 21% │ 52.6 MB │ animir │ enabled │
│ pm2-app-worker │ 4 │ 1.0.0 │ cluster │ 2926 │ online │ 0 │ 32s │ 12% │ 46.4 MB │ animir │ enabled │
└────────────────┴────┴─────────┴─────────┴──────┴────────┴─────────┴────────┴─────┴───────────┴────────┴──────────┘
Get started
Middlewares and plugins
Migration from other packages
Limiters:
- Redis
- Memory
- DynamoDB
- Prisma
- MongoDB (with sharding support)
- PostgreSQL
- MySQL
- BurstyRateLimiter
- Cluster
- PM2 Cluster
- Memcached
- RateLimiterUnion
- RateLimiterQueue
Wrappers:
- RLWrapperBlackAndWhite Black and White lists
Knowledge base:
- Block Strategy in memory
- Insurance Strategy
- Comparative benchmarks
- Smooth out traffic peaks
-
Usage example
- Minimal protection against password brute-force
- Login endpoint protection
- Websocket connection prevent flooding
- Dynamic block duration
- Different limits for authorized users
- Different limits for different parts of application
- Block Strategy in memory
- Insurance Strategy
- Third-party API, crawler, bot rate limiting