1 事务实现:
- 缺点1:非常明显,开启事务后,每个命令都是需要和服务器端多次网络交互,非常浪费;
- 缺点2:不满足原子性,需要Watch加锁机制一起使用,维护复杂
- 缺点3:后执行的命令无法依赖先执行的命令结果,需要Watch加锁机制一起使用,维护复杂
// 开启事务
MULTI
// 删除过期数据
ZREMRANGEBYSCORE <path> 0 <windowStartTimestamp>
// 统计访问次数
ZCARD <path>
// 添加当前时间戳
ZADD <path> <currentTimestamp> <currentTimestamp>
// 设置过期时间
EXPIRE <path> <windowSize>
// 执行事务
EXEC
2 lua脚本实现 注意score精度是52位有效;ns存储可以忽略这个精度?
rdb := redis.NewClient(...)
now := time.Now().UnixNano()
windowSize := int64(time.Second) // 1000000000 NanoSeconds
rateLimit := 1000 // can get from config
luaScript := `local path = KEYS[1]local now = tonumber(ARGV[1])local window = tonumber(ARGV[2])local limit = tonumber(ARGV[3])local clearBefore = now - windowredis.call('ZREMRANGEBYSCORE', path, 0, clearBefore)local amount = redis.call('ZCARD', path)if amount < limit thenredis.call('ZADD', path, now, now)endredis.call('EXPIRE', path, window)return limit - amount
`
vals, err := rdb.Eval(luaScript, // script1, // number of keys[]string{path}, // KEYSnow, // ARGV[1]windowSize, // ARGV[2]rateLimit, // ARGV[3]
).Result()
3. lua脚本单独存储
filename := "/some/path/ratelimiter.lua"
content, err := ioutil.ReadFile(filename)
if err != nil {// handle errorlog.Errorf(err, "Could not read file %s", filename)
}
luaScript := string(content)
vals, err := rdb.Eval(luaScript, // script1, // number of keys[]string{path}, // KEYSnow, // ARGV[1]windowSize, // ARGV[2]rateLimit, // ARGV[3]
).Result()
参考:
Redis: Pipelining, Transactions and Lua Scripts
What is a Rate Limiting Algorithm and How to Build One | Kong Inc.
Redis: Pipelining, Transactions and Lua Scripts
ZADD | Redis
ZCARD | Redis
ZCOUNT | Redis
Building a sliding window rate limiter with Redis — Clarabridge Engage Dev Blog
Error: Internal Rate Limit Reached — Clarabridge Engage Dev Blog
Flowchart Maker & Online Diagram Software
https://medium.com/@saisandeepmopuri/system-design-rate-limiter-and-data-modelling-9304b0d18250
An alternative approach to rate limiting
https://gist.github.com/ptarjan/e38f45f2dfe601419ca3af937fff574d
Scaling your API with rate limiters
GitHub - go-redis/redis: Type-safe Redis client for Golang
redis-geo.lua-golang/redis-geo-lua-example.go at master · abhirockzz/redis-geo.lua-golang · GitHub