24

预案三板斧的限流大法-InfoQ

 4 years ago
source link: https://www.infoq.cn/article/L1FThcLIgzHSYlIaDk0R
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

预案三板斧的限流大法

发布于:2019 年 10 月 21 日 11:56

预案三板斧的限流大法

限流策略:多维防御 + 纵深防御

限流是针对请求的各种特征,多维防御 + 纵深防御,从而限制流量,实现对服务端资源的合理使用。这里的特征是指一个请求所包含的各种信息,包括但不限于 IP、Header、URI、Cookie 等。常见的限流策略有以下三种(以 Nginx 为例进行说明):

  • 限制请求数,意思是请求的次数不能太多

Nginx: http://nginx.org/en/docs/http/ngx_http_limit_req_module.html

  • 限制并发连接数,意思是请求的频率不能太快

Nginx: http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html

  • 限制传输速度,意思是请求的体积不能太大

Nginx: http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate

Nginx 还提供 work_connections 和 worker_processes 这类针对程序的全局设置,但是这些配置并非是客户端的请求的特征,不能直接作用于特定请求特征的流量,因此不属于本文限流的讨论范畴。

所谓的多维防御,不仅仅针对 IP 进行限制,还可以从 URI、Cookie、状态码等多个维度进行限制,同时还可以组合起来进行精细化的限制,举例说明:

  • 状态码 +IP,如果恶意扫描整个网站,必然会出现较多的 404 状态码,这时候结合其他维度,就可以进行一定的防御和限制

  • URI+Cookie,可以避免公司 IP 出口导致的请求被误伤,同时也解决了 IP 模式下阈值设置太大的问题

所谓的纵深防御,则是指针对单一维度,进行多层级的防御,实现精细化的限制。以 IP 维度为例进行说明:

  • 每秒钟,单个 IP 最多可以访问 100 次

  • 每十秒钟,单个 IP 最多可以访问 500 次

  • 每分钟,单个 IP 最多可以访问 1000 次

上述的阈值只是简单举例,并没有太大的参考价值,在实际部署的过程中,一般需要至少 30 天的访问日志以及多个节假日的访问日志进行离线分析,从而得出业务特定的合理阈值,然后在通过灰度逐步全量。初期的阈值,建议设置的比预估阈值至少高一倍,先具备限流功能,然后再慢慢打磨阈值,避免因为阈值设置不合理,导致限流功能上线受阻,那就得不偿失了。

限流的算法

那各种限流策略背后的实现机制是怎样的呢?常见的限流算法有固定窗口计数器,滑动窗口计数器,漏洞和令牌桶四种,在各类软件的具体实现上却不尽相同,详细内容可以参考这篇文章《分布式系统关注点——限流该怎么做?》,本文仅介绍较为常用的两种算法。

固定窗口计数器

将时间划分为固定时间窗口(例如每秒一个单位),在每个固定的时间窗口内对请求进行计数,如果请求的次数超过了限制,则本时间窗口内所有的后续请求都被丢弃,直到下一个固定时间窗口时,重置计数器。

预案三板斧的限流大法

该算法常被吐槽流量突增,举例来说 100r/m(每分钟 100 次请求),可能在第一秒钟就请求完毕,更有甚者,在两个时间窗口交界处可能会产生 2 倍的请求,这样就会导致短时的流量突增。但是,只要把时间粒度控制在秒级,效果还是可以的。因此,滑动窗口就没有太大的必要进行介绍了,大家看相关文章即可。

预案三板斧的限流大法

漏桶算法,有一个固定大小的队列,进入的请求全部放入该队列中,如果队列满,则丢弃进入的请求。同时,以固定的速率从队列中消费请求。好处就是,不管流量进来多少,出去的速率始终固定。

该算法的主要不足就是消费速率设置会偏保守一些,因为不同请求的资源消耗和处理耗时不同,为了能够适配各类场景,必然会导致消费速率设置较为保守。缓解的方法,对不同的请求类型进行集群拆分,从而能够更加精细化的设置消费速率。

预案三板斧的限流大法

各层级限流

全局统一接入:GFE/BFE/JFE

全局统一接入的产品,Goolge 叫做 GFE,Baidu 叫做 BFE,JD 叫做 JFE。这类产品会将公司所有对外流量进行统一的接入和调度,同时具备较强的通用防护能力,如抗 D、WAF 等。

对于一些业务定制化的复杂限流规则,一般会下放到各个业务线自己的接入端来实现。

预案三板斧的限流大法

Webserver:Nginx/OpenResty

上面介绍各种 XFE 的时候提到,一些业务定制化的复杂限流规则,会下放到各个业务线的接入端来实现,在这个阶段,因为 Webserver 的选择较多,所以实现方式也较多,没有统一的标准,一般是直接利用 webserver 提供的限流能力,或者是通过插件方式来实现,前者多以 Nginx 为主,后者则是 Nginx+lua/Nginx+lua+redis 的形式。

本文以 Nginx 为例来进行说明,业务侧的整体思路应该是多维防御 + 纵深防御,从而实现较好的限流效果。

多维防御,以 Nginx 的 limit_req 为例进行说明,不仅仅对来源 IP 进行流控,还可以对请求的 uri,cookie 进行流控,还可以对 ip+uri+cookie 的组合进行流控,从多个维度下手,进而实现更好的效果。

limit_req_zone $ip zone=1:10m rate=100r/s;

limit_req_zone $uri$ip zone=2:10m rate=100r/s;

limit_req_zone $uri$ip$cookie zone=3:10m rate=100r/s;

limit_req zone=1 burst=30 nodelay;

limit_req zone=2 burst=10 nodelay;

limit_req zone=3 burst=30 nodelay;

纵深防御,以 Nginx 的 limit_req 为例进行说明,主要是通过漏斗思路,设置三级防御体系,第一级是粗滤,因此阈值可以设置的较大,仅拦截明显的恶意行为即可,第二级过滤,可以拦截一些异常请求,第三级过滤,则可以将大部分异常请求进行拦截。

limit_req_zone $ip zone=11:10m rate=100r/s;

limit_req_zone $ip zone=12:10m rate=500r/10s;

limit_req_zone $ip zone=13:10m rate=1200r/1m;

limit_req zone=1 burst=50 nodelay;

limit_req zone=2 burst=100 nodelay;

limit_req zone=3 burst=200 nodelay;

备注:Nginx 本身并不支持 500r/10s 这种模式,同时,60r/m 的效果等同于 1r/s,因此上述的配置只能起到一个演示的作用。实际上是需要大家通过插件的方式来实现上述的效果。Nginx 官方对于 r/m 的解释如下:The rate is specified in requests per second (r/s). If a rate of less than one request per second is desired, it is specified in request per minute (r/m). For example, half-request per second is 30r/m.

应用程序和中间件:Istio

对于大部分自研的程序来讲,限流功能如有必要,就得自行实现了,算法前面已经介绍过了,当然,也可以参考 Google 的 RateLimiter。

对于进入了 Docker 的程序,则可以考虑引入 Istio,改造成本可控,收益上,限流,熔断,鉴权等等功能均可具备,但是目前大规模应用的公司还不多,大家都是在慢慢探索中。

对于短期内还无法实现虚拟化的业务,则可以考虑类似 Istio 的模式,在每个程序前,在关键程序前,在和多个下游交互的程序前,适度放置 Proxy 来实现流控的效果。在 AWS 的 Proxy-ELB,就是挂在了每组服务之前。这种模式的缺点就在于会略为增加延时,但如果是同 Regin 部署,那么只要增加的 Proxy 层级数量可控,整体延时影响也可控。

极少数情况下,也有业务直接通过 Iptable 的方式进行限流,对于物理机的部署模式,笔者只能建议要谨慎使用。

参考文章

分布式服务限流实战,已经为你排好坑了

分布式系统关注点——限流该怎么做?

华为交换机设置配置说明

BFE 开源版本


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK