Hammer.Redis.TokenBucket (hammer_backend_redis v7.0.2)
View SourceThis module implements the Token Bucket algorithm. The token bucket algorithm works by modeling a bucket that:
- Fills with tokens at a constant rate (the refill rate)
- Has a maximum capacity of tokens (the bucket size)
- Each request consumes one or more tokens
- If there are enough tokens, the request is allowed
- If not enough tokens, the request is denied
For example, with a refill rate of 10 tokens/second and bucket size of 100:
- Tokens are added at 10 per second up to max of 100
- Each request needs tokens to proceed
- If bucket has enough tokens, request allowed and tokens consumed
- If not enough tokens, request denied until bucket refills
The algorithm:
- When a request comes in, we:
- Calculate tokens added since last request based on time elapsed
- Add new tokens to bucket (up to max capacity)
- Try to consume tokens for the request
- Store new token count and timestamp
- To check if rate limit is exceeded:
- If enough tokens: allow request and consume tokens
- If not enough: deny and return time until enough tokens refill
- Old entries are automatically cleaned up after expiration
This provides smooth rate limiting with ability to handle bursts up to bucket size. The token bucket is a good choice when:
- You need to allow temporary bursts of traffic
- Want to enforce an average rate limit
- Need to support different costs for different operations
- Want to avoid the sharp edges of fixed windows
Common use cases include:
- API rate limiting with burst tolerance
- Network traffic shaping
- Resource allocation control
- Gaming systems with "energy" mechanics
- Scenarios needing flexible rate limits
The main advantages are:
- Natural handling of bursts
- Flexible token costs for different operations
- Smooth rate limiting behavior
- Simple to reason about
The tradeoffs are:
- Need to track token count and last update time
- May need tuning of bucket size and refill rate
- More complex than fixed windows
For example with 100 tokens/minute limit and 500 bucket size:
- Can handle bursts using saved up tokens
- Automatically smooths out over time
- Different operations can cost different amounts
- More flexible than fixed request counts
Example usage:
defmodule MyApp.RateLimit do
use Hammer, backend: Hammer.Redis, algorithm: :token_bucket
end
MyApp.RateLimit.start_link(clean_period: :timer.minutes(1))
# Allow 10 tokens per second with max capacity of 100
MyApp.RateLimit.hit("user_123", 10, 100, 1)
Summary
Functions
Returns the current level of the bucket for a given key.
Functions
@spec get( connection_name :: atom(), prefix :: String.t(), key :: String.t(), timeout :: non_neg_integer() ) :: non_neg_integer()
Returns the current level of the bucket for a given key.