不论是在单体服务中还是在微服务中,开发者为前端提供的API接口都是有拜访下限的,当拜访频率或者并发量超过其接受范畴时候,咱们就必须思考限流来保障接口的可用性或者降级可用性。即接口也须要装置上保险丝,以避免非预期的申请对系统压力过大而引起的零碎瘫痪。
go-zero
periodlimittokenlimit
periodlimit
应用
const (
seconds = 1
total = 100
quota = 5
)
// New limiter
l := NewPeriodLimit(seconds, quota, redis.NewRedis(s.Addr(), redis.NodeType), "periodlimit")
// take source
code, err := l.Take("first")
if err != nil {
logx.Error(err)
return true
}
// switch val => process request
switch code {
case limit.OverQuota:
logx.Errorf("OverQuota key: %v", key)
return false
case limit.Allowed:
logx.Infof("AllowedQuota key: %v", key)
return true
case limit.HitQuota:
logx.Errorf("HitQuota key: %v", key)
// todo: maybe we need to let users know they hit the quota
return false
default:
logx.Errorf("DefaultQuota key: %v", key)
// unknown response, we just let the sms go
return true
}
periodlimit
go-zerolimitlimit
而在一个分布式系统中,存在多个微服务提供服务。所以当霎时的流量同时拜访同一个资源,如何让计数器在分布式系统中失常计数? 同时在计算资源拜访时,可能会波及多个计算,如何保障计算的原子性?
go-zeroredisincrbylua script
lua script
argument | mean |
---|---|
key[1] | 拜访资源的标示 |
ARGV[1] | limit => 申请总数,超过则限速。可设置为 QPS |
ARGV[2] | window大小 => 滑动窗口,用 ttl 模拟出滑动的成果 |
-- to be compatible with aliyun redis,
-- we cannot use `local key = KEYS[1]` to reuse thekey
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
-- incrbt key 1 => key visis++
local current = redis.call("INCRBY", KEYS[1], 1)
-- 如果是第一次拜访,设置过期工夫 => TTL = window size
-- 因为是只限度一段时间的拜访次数
if current == 1 then
redis.call("expire", KEYS[1], window)
return 1
elseif current < limit then
return 1
elseif current == limit then
return 2
else
return 0
end
return code
return code | tag | call code | mean |
---|---|---|---|
0 | OverQuota | 3 | over limit |
1 | Allowed | 1 | in limit |
2 | HitQuota | 2 | hit limit |
limit
后续解决
periodlimitlimit
periodlimitcode
mqtokenlimit
tokenlimit
总结
go-zeroperiodlimitredisredis lua script
然而这种计划也存在毛病,因为它要记录时间窗口内的所有行为记录,如果这个量特地大的时候,内存耗费会变得十分重大。
参考
- go-zero periodlimit
- 分布式服务限流实战,曾经为你排好坑了
go-zero
如果感觉文章不错,欢送github点个star ????
我的项目地址:
https://github.com/tal-tech/go-zero