UNPKG

rate-limiter-flexible

Version:

Flexible API rate limiter backed by Redis for distributed node.js applications

88 lines (66 loc) 2.54 kB
## RateLimiterCluster ### Benchmark Endpoint is pure NodeJS endpoint launched in `node:latest` and `redis:alpine` Docker containers with 4 workers Endpoint is limited by `RateLimiterCluster` with config: ```javascript new RateLimiterCluster({ points: 1000, duration: 1, }); ``` By `bombardier -c 1000 -l -d 30s -r 2000 -t 5s http://127.0.0.1:8000` Test with 1000 concurrent requests with maximum 2000 requests per sec during 30 seconds ```text Statistics Avg Stdev Max Reqs/sec 2024.57 234.52 2976.20 Latency 704.58us 165.65us 7.05ms Latency Distribution 50% 669.00us 75% 843.00us 90% 1.02ms 95% 1.18ms 99% 1.60ms HTTP codes: 1xx - 0, 2xx - 53458, 3xx - 0, 4xx - 6560, 5xx - 0 ``` Cluster limiter at least twice faster than RateLimiterRedis. ### How it works RateLimiterClusterMaster must be created in master process. It receives messages from workers by IPC. It creates necessary message handler, which process messages only from specific channel `rate_limiter_flexible`. So if you use IPC for something else, it doesn't break anything. ```javascript const { RateLimiterClusterMaster } = require('rate-limiter-flexible'); if (cluster.isMaster) { new RateLimiterClusterMaster(); cluster.fork(); } else { // ... your app ... } ``` RateLimiterClusterMaster is Singleton. It creates only one instance which process messages from all RateLimiterCluster created in workers. RateLimiterCluster must be created with unique `keyPrefix`. Every time RateLimiterCluster is created, it sends options to master. Master instance creates specific rate limiter by `keyPrefix` and sends `init` command to worker So there is a time when worker can't process requests until master sends `init` to worker. It takes several milliseconds. Worker is protected from loosing requests while it is instantiated. It sets timer for 30 ms and waits `init` from master before processing requests ### Create several rate limiters ```javascript const rateLimiter1 = new RateLimiterCluster({ keyPrefix: 'limiter1', points: 100, duration: 1, }); const rateLimiter2 = new RateLimiterCluster({ keyPrefix: 'limiter2', points: 10, duration: 1, execEvenly: true }); ``` If the second `keyPrefix` is the same `limiter1`, master doesn't create the second limiter. This results to unexpected behaviour, because options from the first limiter are used. **`keyPrefix` must be unique, if different options required**