search
HomeDatabaseRedisHow to implement the token bucket algorithm using Redis? (with code)

This article will share with you the principle of the token bucket algorithm and introduce the method of using Redis to implement the token bucket algorithm. I hope it will be helpful to everyone!

How to implement the token bucket algorithm using Redis? (with code)

Among the current limiting algorithms, there is a token bucket algorithm, which can deal with short bursts of traffic, which is particularly useful in real-life environments where the traffic is not very uniform. , the current limit will not be triggered frequently, and it is more friendly to the caller.

For example, the current limit is 10qps. Most of the time it will not exceed this amount, but occasionally it will reach 30qps and then return to normal soon. It is assumed that this burst of traffic will not have an impact on system stability. , we can allow this instantaneous burst traffic to a certain extent, thereby bringing a better availability experience to users. This is where the token bucket algorithm comes in.

Token Bucket Algorithm Principle

As shown in the figure below, the basic principle of the algorithm is: there is a token bucket with a capacity of into this bucket. If the number of tokens in the bucket exceeds X, then it will be discarded. When processing a request, you need to first remove the token from the token bucket. If you get the token, continue processing; if you cannot get the token, reject the request.

How to implement the token bucket algorithm using Redis? (with code)

It can be seen that it is particularly important to set the number of X, Y and Z in the token bucket algorithm. Z should be slightly larger than the number of requests per Y unit time, and the system will be in this state for a long time; This indicates that the traffic has exceeded expectations, and the cause needs to be investigated promptly and corresponding measures taken.

Redis implements the token bucket algorithm

I have seen token buckets implemented by some programs before. The method of putting tokens into the bucket is to start a thread. Increase the number of tokens every Y unit time, or execute this process regularly in Timer. I am not very satisfied with this method. There are two reasons. One is a waste of thread resources, and the other is the inaccurate execution time due to scheduling issues. [Related recommendations: Redis Video Tutorial]

The method to determine the number of tokens in the token bucket is through calculation. First, calculate how much time has passed from the last request to this request. For a long time, whether the time threshold for issuing tokens is reached, then how many tokens are added, and how many of these tokens can be put into the bucket.

Talk is cheap!

Let’s take a look at how it is implemented in Redis. Because it involves multiple interactions with Redis, here in order to improve the throughput of current limiting processing and reduce program and The number of Redis interactions uses Lua script supported by Redis. The execution of Lua script is atomic, so there is no need to worry about dirty data.

The code is excerpted from FireflySoft.RateLimit. It not only supports ordinary master-slave deployment of Redis, but also supports clustered Redis, so throughput can be improved through horizontal expansion. For the convenience of reading, some comments are added here, but there are actually none.

-- 定义返回值,是个数组,包含:是否触发限流(1限流 0通过)、当前桶中的令牌数
local ret={}
ret[1]=0
-- Redis集群分片Key,KEYS[1]是限流目标
local cl_key = '{' .. KEYS[1] .. '}'

-- 获取限流惩罚的当前设置,触发限流惩罚时会写一个有过期时间的KV
-- 如果存在限流惩罚,则返回结果[1,-1]
local lock_key=cl_key .. '-lock'
local lock_val=redis.call('get',lock_key)
if lock_val == '1' then
    ret[1]=1
    ret[2]=-1
    return ret;
end

-- 这里省略部分代码

-- 获取[上次向桶中投放令牌的时间],如果没有设置过这个投放时间,则令牌桶也不存在,此时:
-- 一种情况是:首次执行,此时定义令牌桶就是满的。
-- 另一种情况是:较长时间没有执行过限流处理,导致承载这个时间的KV被释放了,
-- 这个过期时间会超过自然投放令牌到桶中直到桶满的时间,所以令牌桶也应该是满的。
local last_time=redis.call('get',st_key)
if(last_time==false)
then
 -- 本次执行后剩余令牌数量:桶的容量- 本次执行消耗的令牌数量
    bucket_amount = capacity - amount;
    -- 将这个令牌数量更新到令牌桶中,同时这里有个过期时间,如果长时间不执行这个程序,令牌桶KV会被回收
    redis.call('set',KEYS[1],bucket_amount,'PX',key_expire_time)
    -- 设置[上次向桶中放入令牌的时间],后边计算应放入桶中的令牌数量时会用到
    redis.call('set',st_key,start_time,'PX',key_expire_time)
    -- 返回值[当前桶中的令牌数]
    ret[2]=bucket_amount
    -- 无需其它处理
    return ret
end

-- 令牌桶存在,获取令牌桶中的当前令牌数
local current_value = redis.call('get',KEYS[1])
current_value = tonumber(current_value)

-- 判断是不是该放入新令牌到桶中了:当前时间-上次投放的时间 >= 投放的时间间隔
last_time=tonumber(last_time)
local last_time_changed=0
local past_time=current_time-last_time
if(past_time<inflow_unit)
then
 -- 不到投放的时候,直接从令牌桶中取走令牌
    bucket_amount=current_value-amount
else
 -- 需要放入一些令牌, 预计投放数量 = (距上次投放过去的时间/投放的时间间隔)*每单位时间投放的数量
    local past_inflow_unit_quantity = past_time/inflow_unit
    past_inflow_unit_quantity=math.floor(past_inflow_unit_quantity)
    last_time=last_time+past_inflow_unit_quantity*inflow_unit
    last_time_changed=1
    local past_inflow_quantity=past_inflow_unit_quantity*inflow_quantity_per_unit
    bucket_amount=current_value+past_inflow_quantity-amount
end

-- 这里省略部分代码

ret[2]=bucket_amount

-- 如果桶中剩余数量小于0,则看看是否需要限流惩罚,如果需要则写入一个惩罚KV,过期时间为惩罚的秒数
if(bucket_amount<0)
then
    if lock_seconds>0 then
        redis.call(&#39;set&#39;,lock_key,&#39;1&#39;,&#39;EX&#39;,lock_seconds,&#39;NX&#39;)
    end
    ret[1]=1
    return ret
end

-- 来到这里,代表可以成功扣减令牌,则需要更新令牌桶KV
if last_time_changed==1 then
    redis.call(&#39;set&#39;,KEYS[1],bucket_amount,&#39;PX&#39;,key_expire_time)
 -- 有新投放,更新[上次投放时间]为本次投放时间
    redis.call(&#39;set&#39;,st_key,last_time,&#39;PX&#39;,key_expire_time)
else
    redis.call(&#39;set&#39;,KEYS[1],bucket_amount,&#39;PX&#39;,key_expire_time)
end
return ret

Through the above code, it can be seen that the main processing process is:

1. Determine whether there is a current limit penalty. If so, return directly. If not, go to the next step.

2. Determine whether the token bucket exists. If it does not exist, create the token bucket first, then deduct the token and return it. If it exists, go to the next step.

3. Determine whether tokens need to be issued. If not, the tokens will be deducted directly. If necessary, tokens will be issued first and then the tokens will be deducted.

4. Determine the number of tokens after deduction. If it is less than 0, return the current limit, and set the current limit penalty. If it is greater than or equal to 0, go to the next step.

5. Update the number of tokens in the bucket to Redis.

You can submit and run this Lua script in the Redis library of any development language. If you are using the .NET platform, you can refer to this article: ASP.NET Core Use token bucket rate limit (https://blog.bossma.cn/dotnet/asp-net-core-token-bucket-algorithm-of-rate-limit/).

About FireflySoft.RateLimit

FireflySoft.RateLimit is a current limiting class library based on .NET Standard. Its core is simple and lightweight, and can flexibly cope with various Demand current limiting scenarios.

Its main features include:

  • Multiple current limiting algorithms: built-in four algorithms: fixed window, sliding window, leaky bucket, and token bucket, which can also be customized and expanded.
  • Multiple counting storage: currently supports two storage methods: memory and Redis.
  • Distributed friendly: Supports unified counting of distributed programs through Redis storage.
  • Flexible current limiting target: Various data can be extracted from the request to set the current limiting target.
  • Support current limiting penalty: you can lock the client for a period of time after triggering current limiting and not allow access.
  • Dynamic change rules: Supports dynamically changing current limiting rules while the program is running.
  • Customized error: You can customize the error code and error message after triggering the current limit.
  • Universal applicability: In principle, it can meet any scenario that requires current limiting.

Github open source address: https://github.com/bosima/FireflySoft.RateLimit/blob/master/README.zh-CN.md

This article is reproduced from: https://juejin.cn/post/7039105263168651301

Author: Yinghuo Architecture

For more programming-related knowledge, please visit: Programming video! !

The above is the detailed content of How to implement the token bucket algorithm using Redis? (with code). For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:掘金社区. If there is any infringement, please contact admin@php.cn delete
Redis: Exploring Its Features and FunctionalityRedis: Exploring Its Features and FunctionalityApr 19, 2025 am 12:04 AM

Redis stands out because of its high speed, versatility and rich data structure. 1) Redis supports data structures such as strings, lists, collections, hashs and ordered collections. 2) It stores data through memory and supports RDB and AOF persistence. 3) Starting from Redis 6.0, multi-threaded I/O operations have been introduced, which has improved performance in high concurrency scenarios.

Is Redis a SQL or NoSQL Database? The Answer ExplainedIs Redis a SQL or NoSQL Database? The Answer ExplainedApr 18, 2025 am 12:11 AM

RedisisclassifiedasaNoSQLdatabasebecauseitusesakey-valuedatamodelinsteadofthetraditionalrelationaldatabasemodel.Itoffersspeedandflexibility,makingitidealforreal-timeapplicationsandcaching,butitmaynotbesuitableforscenariosrequiringstrictdataintegrityo

Redis: Improving Application Performance and ScalabilityRedis: Improving Application Performance and ScalabilityApr 17, 2025 am 12:16 AM

Redis improves application performance and scalability by caching data, implementing distributed locking and data persistence. 1) Cache data: Use Redis to cache frequently accessed data to improve data access speed. 2) Distributed lock: Use Redis to implement distributed locks to ensure the security of operation in a distributed environment. 3) Data persistence: Ensure data security through RDB and AOF mechanisms to prevent data loss.

Redis: Exploring Its Data Model and StructureRedis: Exploring Its Data Model and StructureApr 16, 2025 am 12:09 AM

Redis's data model and structure include five main types: 1. String: used to store text or binary data, and supports atomic operations. 2. List: Ordered elements collection, suitable for queues and stacks. 3. Set: Unordered unique elements set, supporting set operation. 4. Ordered Set (SortedSet): A unique set of elements with scores, suitable for rankings. 5. Hash table (Hash): a collection of key-value pairs, suitable for storing objects.

Redis: Classifying Its Database ApproachRedis: Classifying Its Database ApproachApr 15, 2025 am 12:06 AM

Redis's database methods include in-memory databases and key-value storage. 1) Redis stores data in memory, and reads and writes fast. 2) It uses key-value pairs to store data, supports complex data structures such as lists, collections, hash tables and ordered collections, suitable for caches and NoSQL databases.

Why Use Redis? Benefits and AdvantagesWhy Use Redis? Benefits and AdvantagesApr 14, 2025 am 12:07 AM

Redis is a powerful database solution because it provides fast performance, rich data structures, high availability and scalability, persistence capabilities, and a wide range of ecosystem support. 1) Extremely fast performance: Redis's data is stored in memory and has extremely fast read and write speeds, suitable for high concurrency and low latency applications. 2) Rich data structure: supports multiple data types, such as lists, collections, etc., which are suitable for a variety of scenarios. 3) High availability and scalability: supports master-slave replication and cluster mode to achieve high availability and horizontal scalability. 4) Persistence and data security: Data persistence is achieved through RDB and AOF to ensure data integrity and reliability. 5) Wide ecosystem and community support: with a huge ecosystem and active community,

Understanding NoSQL: Key Features of RedisUnderstanding NoSQL: Key Features of RedisApr 13, 2025 am 12:17 AM

Key features of Redis include speed, flexibility and rich data structure support. 1) Speed: Redis is an in-memory database, and read and write operations are almost instantaneous, suitable for cache and session management. 2) Flexibility: Supports multiple data structures, such as strings, lists, collections, etc., which are suitable for complex data processing. 3) Data structure support: provides strings, lists, collections, hash tables, etc., which are suitable for different business needs.

Redis: Identifying Its Primary FunctionRedis: Identifying Its Primary FunctionApr 12, 2025 am 12:01 AM

The core function of Redis is a high-performance in-memory data storage and processing system. 1) High-speed data access: Redis stores data in memory and provides microsecond-level read and write speed. 2) Rich data structure: supports strings, lists, collections, etc., and adapts to a variety of application scenarios. 3) Persistence: Persist data to disk through RDB and AOF. 4) Publish subscription: Can be used in message queues or real-time communication systems.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Tools

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.