美文网首页
go-zero 如何扛住流量冲击(一)

go-zero 如何扛住流量冲击(一)

作者: kevwan | 来源:发表于2020-11-17 12:00 被阅读0次

不管是在单体服务中还是在微服务中,开发者为前端提供的API接口都是有访问上限的,当访问频率或者并发量超过其承受范围时候,我们就必须考虑限流来保证接口的可用性或者降级可用性。即接口也需要安装上保险丝,以防止非预期的请求对系统压力过大而引起的系统瘫痪。

go-zero 集成了开箱即用的 限流器 。其中内置了两种限流器,也对应两类使用场景:

种类 原理 场景
periodlimit 单位时间限制访问次数 需要强行限制数据的传输速率
tokenlimit 令牌桶限流 限制数据的平均传输速率,同时允许某种程度的突发传输

本文就来介绍一下 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-zero 采取 滑动窗口 计数的方式,计算一段时间内对同一个资源的访问次数,如果超过指定的 limit ,则拒绝访问。当然如果你是在一段时间内访问不同的资源,每一个资源访问量都不超过 limit ,此种情况是允许大量请求进来的。

而在一个分布式系统中,存在多个微服务提供服务。所以当瞬间的流量同时访问同一个资源,如何让计数器在分布式系统中正常计数? 同时在计算资源访问时,可能会涉及多个计算,如何保证计算的原子性?

  • go-zero 借助 redisincrby 做资源访问计数
  • 采用 lua 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 时后续发生的情况:

后续处理

如果在服务某个时间点,请求大批量打进来,periodlimit 短期时间内达到 limit 阈值,而且设置的时间范围还远远没有到达。后续请求的处理就成为问题。

periodlimit 中并没有处理,而是返回 code 。把后续请求的处理交给了开发者自己处理。

  1. 如果不做处理,那就是简单的将请求拒绝
  2. 如果需要处理这些请求,开发者可以借助 mq 将请求缓冲,减缓请求的压力
  3. 采用 tokenlimit,允许暂时的流量冲击

所以下一篇我们就来聊聊 tokenlimit

总结

go-zero 中的 periodlimit 限流方案是基于 redis 计数器,通过调用 redis lua script ,保证计数过程的原子性,同时保证在分布式的情况下计数是正常的。

但是这种方案也存在缺点,因为它要记录时间窗口内的所有行为记录,如果这个量特别大的时候,内存消耗会变得非常严重。

参考

同时欢迎大家使用 go-zero 并加入我们,https://github.com/tal-tech/go-zero

如果觉得文章不错,欢迎github点个star 👏

项目地址:
https://github.com/tal-tech/go-zero

相关文章

  • go-zero 如何扛住流量冲击(二)

    本篇文章承接上一篇go-zero 如何扛住流量冲击(一)[https://gocn.vip/topics/1124...

  • go-zero 如何扛住流量冲击(一)

    不管是在单体服务中还是在微服务中,开发者为前端提供的API接口都是有访问上限的,当访问频率或者并发量超过其承受范围...

  • 12306能扛住明星出轨这种流量冲击吗?

    出品 | AI科技大本营 2019 年的春运将于明天正式开启,据国务院新闻办公室 18 日在新闻发布会上的介绍,今...

  • 扛住

    作为一个成年人,往往要一个人默默承受生活带给你的苦涩,疾病带给你的折磨,唯有坚强不屈才能慢慢走向光明!加油!

  • 扛住

    又是昏沉沉的一天。 抬头看看外头的天,灰蒙蒙的,一点没有初夏的感觉。最近身体状况不太好,时不时会头晕,广告里说心随...

  • 扛住

    工作头绪太多,想做的太多,都不是自己想做的。 怎么办,感觉都扛不住了。 想走人,但是没有办法。不让走。 扛不住,就...

  • 扛住

    日更day219/y4 --------------------------- 情绪真的要扛不住了。 业绩的低迷,...

  • 扛住

    全世界都进入了羊圈,谁能进决赛,这就是拼自身免疫力的时候了。 班里有学生羊了,女儿班里也是,所以两个班同时停课提前...

  • go-zero 实战之 blog 系统

    go-zero 实战项目:blog 本文以 blog 的网站后台为例,着重介绍一下如何使用 go-zero 开发 ...

  • 成长锦囊[95]:要建立好的个人成长系统,请坚持这个习惯

    Q:素心,如今疫情、裁员、断供,周围充斥着各种不确定性,我感觉能扛住风险也是一个优秀的品质,如何让自己能扛住风险?...

网友评论

      本文标题:go-zero 如何扛住流量冲击(一)

      本文链接:https://www.haomeiwen.com/subject/vtjxiktx.html