服务端接口限流设计

限流简介

什么是限流

  • 在不同场景下限流的定义也各不相同,可以是每秒请求数、每秒事务处理数、网络流量。
  • 通常我们所说的限流指的是限制到达系统并发请求数,使得系统能够正常的处理部分用户的请求,来保证系统的稳定性。

为什么限流

接口无法控制调用方的行为。热点业务突发请求、恶意请求攻击等会带来瞬时的请求量激增,导致服务占用大量的 CPU、内存等资源,使得其他正常的请求变慢或超时,甚至引起服务器宕机。
按照请求次数进行收费的接口需要根据客户支付的金额来限制客户可用的次数。

限流的行为

  • 拒绝服务:把多出来的请求拒绝掉
  • 服务降级:关闭或是把后端服务做降级处理。这样可以让服务有足够的资源来处理更多的请求
  • 特权请求:资源不够了,我只能把有限的资源分给重要的用户
  • 延时处理:一般会有一个队列来缓冲大量的请求,这个队列如果满了,那么就只能拒绝用户了,如果这个队列中的任务超时了,也要返回系统繁忙的错误了
  • 弹性伸缩:用自动化运维的方式对相应的服务做自动化的伸缩

限流算法

固定窗口

描述:将时间划分为多个窗口,在单个窗口内每有一次请求就将计数器加一,如果计数器超过了限制数量,则本窗口内所有的请求都被丢弃;当时间到达下一个窗口是,计数器重置。

  • 优点:实现简单
  • 缺点:有“突刺现象“,无法应对两个时间窗口临界时间内的突发流量 而且存在"两倍配置速率问题"
    服务端接口限流设计_第1张图片
滑动窗口

描述:将时间划分为多个区间,单个区间内每有一次请求就将计数器加一,维持一时间窗口,占据多个区间;每经过一个区间的时间则抛弃最老的区间,并纳入最新的一个区间。TCP协议中数据包的传输,同样也是采用滑动窗口来进行流量控制。

  • 优点:实现不算复杂,解决了“两倍配置速率”的问题
  • 缺点:“突刺现象”依旧存在,无法应对两个时间窗口临界时间内的突发流量
    服务端接口限流设计_第2张图片

服务端接口限流设计_第3张图片

令牌桶算法

描述:令牌以固定速率生成;生成的令牌放入令牌桶中存放,如果令牌桶满了则多余的令牌会直接丢弃,当请求到达时,会尝试从令牌桶中取令牌,取到了令牌的请求可以执行;如果桶空了,那么尝试取令牌的请求会被抛弃

  • 优点:解决了突发大量请求的问题,令牌桶算法可以把请求平均分散在时间段内
  • 缺点:每个请求必须从令牌桶取令牌,如果请求量巨大,会对令牌桶的性能要求非常高

Nginx 中的 limit_req 模块的底层实现就是用的这种算法,具体可参考【NGINX 和 NGINX Plus 的速率限制】(https://www.nginx.com/blog/rate-limiting-nginx)
服务端接口限流设计_第4张图片

漏桶限流算法

描述:将每个请求当做“水滴”放入漏桶进行存储;漏桶以固定速率向外“漏”出请求来执行;如果漏桶空了则停止“漏水”;如果漏桶满了则多余的“水滴”(请求)被被直接抛弃

  • 优点:解决了突刺现象

  • 缺点:当短时间内有大量的突发请求时,即便此时服务器没有任何负载,每个请求也得在队列当中等一段时间才能被响应
    服务端接口限流设计_第5张图片

限流方法

单点限流
  • 单点限流,实现较为简单;缺陷是无法对整个所有服务实例做限流
分布式限流
  • 基于某种中间件的限流方式,实现较复杂;但可以对整个服务全部实例子进行限流
限流维度
service维度
  • 针对某个服务方统一限流
接口维度
  • 针对单个接口维度的限制

文档参考

  • https://www.infoq.cn/article/microservice-interface-rate-limit
  • https://github.com/RussellLuo/slidingwindow
  • https://github.com/juju/ratelimit
  • https://pkg.go.dev/golang.org/x/time/rate
  • https://github.com/uber-go/ratelimit
  • https://github.com/go-redis/redis_rate

你可能感兴趣的:(架构设计,后端)