Package: redbucket
Red BucketPython rate limiting library using Redis for shared state.InstallationTo install the latest released version:pip install redbucketTo install the current development version from the master branch on GitHub:pip install -U git+https://github.com/nickgaya/redbucket.gitUsageThe following snippet configures a rate limiter with two rate limiting zones:fromredbucketimportRedisRateLimiter,RateLimit,ZonefromredisimportRedis# Accept up to 5 requests per user per second.# Allow bursts of up to 10 requests.user_zone=Zone('user',rate=5)user_limit=RateLimit(user_zone,burst=10)# Accept up to 20 requests per IP per second.# Allow up to 10 excess requests with a delay.ip_zone=Zone('ip',rate=20)ip_limit=RateLimit(ip_zone,delay=10)redis=Redis()rate_limiter=RedisRateLimiter(redis)rate_limiter.configure(user=user_limit,ip=ip_limit)We can now use the rate limiter as follows:defexample_operation(user,ip_address):response=rate_limiter.request(user=user,ip=ip_address)ifnotresponse.accepted:raiseException("Rate limit exceeded")# Reject requestifresponse.delay>0:sleep(response.delay)# Wait for delay seconds...# Perform operationNote that we don't have to specify a key for every zone. For example, we could
exclude certain IP addresses from IP rate limiting while still applying the
user rate limit, as follows:defexample_operation(user,ip_address):ifis_whitelisted(ip_address):response=rate_limiter.acquire(user=user)else:response=rate_limiter.acquire(user=user,ip=ip_address)...ImplementationsThe defaultRedisRateLimiteruses Redis's Lua script engine to atomically
update rate limiter state. This implementation requires Redis 3.2 or greater.
For older Redis versions, you can use theRedisTransactionalRateLimiter.Where supported, the script-based implementation is recommended as it handles
each rate limiting request in a single round-trip to the Redis server, whereas
the transactional implementation performs several consecutive Redis commands
per request.State encodingBy default, rate limiter state is stored in Redis using a packed binary
representation. You can switch to JSON for a less efficient but more
human-readable encoding.rate_limiter = RedisRateLimiter(redis, codec='json')Rate limiting modelRed Bucket uses a rate limiting model inspired byNginx.
Rate limiting state is stored in one or morezones. Each zone has a name
and a baserate. A zone represents a namespace of rate limitingkeys. Arate limitreferences a zone along with two parameters,burstanddelay. Arate limiterreferences one or more rate limits.To apply rate limiting to an operation, the application makes arequestto
the rate limiter by specifying a key for each desired rate limit. The rate
limiter evaluates each rate limit to determine whether to reject, delay, or
immediately accept the request. If using multiple rate limits, the most
restrictive outcome will be applied.For a rate limit with base rater, burst valueb, and delay valued, the rate limiter maintains a virtual counter for each key that
continuously increases at a rate ofrrequests per second up to a
maximum value ofb+ 1. When a request arrives,
the rate limiter checks the current value of the counterv. Ifv− 1 ≥ 0, the rate
limiter decrements the counter by 1 and accepts the request immediately. Ifv− 1 ≥ −d,
the rate limiter decrements the counter by 1 and accepts the request after a
delay of(v− 1) /rseconds. Otherwise,i.e.ifv− 1 < −d,
the rate limiter rejects the request.In practice, this means that from an initial idle state for a given key, the
rate limiter will allow a burst ofb+ 1requests immediately,
throttle the nextdrequests to the desired rate, and reject any further
requests past the limit.Comparison with NginxAs noted above, Red Bucket's rate limiting model is inspired by Nginx and
uses a similar algorithm. However, the way burst and delay are specified is a
little different. The following configuration examples illustrate the
difference.Basic rate limiting# nginxlimit_reqzone=mylimit;# redbucketRateLimit(zone=mylimit)Burst with delay# nginxlimit_reqzone=mylimitburst=20;# redbucketRateLimit(zone=mylimit,delay=20)Burst with no delay# nginxlimit_reqzone=mylimitburst=20nodelay;# redbucketRateLimit(zone=mylimit,burst=20)Two-stage rate limiting# nginxlimit_reqzone=ipburst=12delay=8;# redbucketRateLimit(zone=mylimit,burst=8,delay=4)DevelopmentThis project uses Tox to manage virtual environments for unit tests and other
checks. Unit tests are written using the Pytest framework.The unit tests require a Redis instance. By default, the tests attempt to
connect to port 6379 of localhost. This can be overridden by setting theREDIS_URLenvironment variable.export REDIS_URL=redis://localhost:6379To start a Redis Docker container for running the tests, you can use thedocker_redis.shscript. For example, to run the tests against a Docker redis
instance, you can run:./docker_redis.sh toxYou can also run the script without a command and execute output to set
environment variables in your current shell.eval "$(./docker_redis.sh)"By default, the script uses theredis:alpineimage. You can supply a
different tag for theredisimage with the-tflag, or a different image
name with-i.