redis Several ways to implement the speed limiter.
GET INCR EXPIRE
Get the current value of key first. If it does not exceed the limit, execute INCR and increment it by 1. If key does not exist, use the transaction of redis to initialize key and Expiration.
(Recommended: redis video tutorial)
Pseudo code:
count = redis.GET(key) if redis return nil { redis.MULTI redis.INCR(key) redis.EXPIRE(key, expire_time) redis.EXEC count = 1 } if count > limit { return 超出限制 } else { redis.INCR(key) }
Problems under high concurrency:
If 10 at the same time If a concurrent program executes GET and returns nil, then these 10 concurrent programs will execute redis transactions to increase key by one, but the count value of each program is 1. If the value set by limit is less than 10, then the program that is actually executed will The limit has been exceeded. If redis is checked again after executing the transaction and assigned to count, then each program may return 10, so no program can continue to execute.
When the key already exists, the logic of GET first and then INCR may also cause the number of actually executed programs to exceed the limit.
INCR EXPIRE
First INCR, if the value is 1, it means that the key has just been set, then execute EXPIRE
Pseudo code:
count = redis.INCR(key) if count == 1 { redis.EXPIRE(key, expire_time) } if count > limit { return 超出限制 }
Use with caution
If the program hangs after INCR and EXPIRE is not executed, then the key will have no expiration time. The specific impact depends on the needs.
lua script
local current current = redis.call("incr",KEYS[1]) if tonumber(current) == 1 then redis.call("expire",KEYS[1],1) end
For more redis knowledge, please pay attention to the redis introductory tutorial column.
The above is the detailed content of Several ways to implement speed limiter in redis. For more information, please follow other related articles on the PHP Chinese website!