【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

预案三板斧的限流大法

  • 2019-10-21
  • 本文字数:2794 字

    阅读完需:约 9 分钟

预案三板斧的限流大法

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

限流能力

限流是针对请求的各种特征,多维防御+纵深防御,从而限制流量,实现对服务端资源的合理使用。这里的特征是指一个请求所包含的各种信息,包括但不限于 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 ip zone=2:10m rate=100r/s;


limit_req_zone 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开源版本


2019-10-21 11:5612443

评论

发布
暂无评论
发现更多内容

跟着卷卷龙一起学Camera--CameraService

卷卷龙

ISP 9月月更

阿里前端常见面试题总结

loveX001

JavaScript 前端

户外LED广告屏如何才能保养好?

Dylan

LED显示屏 led显示屏厂家

C++学习---cstdio的源码学习分析02-文件删除函数remove

桑榆

c++ 源码阅读 9月月更

【蓝桥杯Web】2022年第十三届蓝桥杯Web大学组省赛真题解析(完整版)

海底烧烤店ai

算法 前端 JavaScrip 9月月更

mysql实数类型和字符串类型

急需上岸的小谢

9月月更

手把手教你如何使用 Timestream 实现物联网时序数据存储和分析

亚马逊云科技 (Amazon Web Services)

数据分析 物联网 数据存储

【Vue3】 评论列表(简易)-- 思路与实现分析

Sam9029

JavaScript Vue Vue3 9月月更

SpringBoot数据库管理 - 用Liquibase对数据库管理和迁移?

Java快了!

数据库 spring-boot

Plato Labs推出的SeedX,公测15天570万美金净利润

鳄鱼视界

NtyCo纯C协程的原理分析

C++后台开发

后台开发 协程 后端开发 异步IO C++开发

白天建筑师,晚上CG艺术家,他将建筑的华丽发挥极致

Renderbus瑞云渲染农场

云渲染 云渲染农场 渲染农场

Elasticsearch聚合学习之四:结果排序

程序员欣宸

elasticsearch 9月月更

继GitHub的Copilot收费后,亚马逊推出了 CodeWhisperer,感觉不错哟!

Python猫

Python

Redis命令传播的心跳检测

急需上岸的小谢

9月月更

MFC与Qt多个控件响应统一响应消息处理

中国好公民st

c++ qt 9月月更

DPDK源码分析之DPDK基础概览

于顾而言

DPDK DPDK开发

超详细:这份全网首发的Kafka技术手册,从基础到实战一应俱全!

收到请回复

Java 云计算 开源 架构 编程语言

5 个 Promise 要避免的常见用法~

掘金安东尼

前端 9月月更

Java 多线程:并发编程的三大特性

Java快了!

Java多线程

羊了个羊”通关修改思路

Java-fenn

Java

Java程序员:为了跳槽刷完1000道真题,没想到老板直接给我升职了!

收到请回复

Java 云计算 开源 架构 编程语言

只要32天就能拿下Offer?框架+性能优化+微服务+分布式,Java程序员必备!

收到请回复

Java 云计算 开源 架构 编程语言

【蓝桥杯Web】2022年第十三届蓝桥杯Web大学组省赛真题解析(精华版)

海底烧烤店ai

算法 前端 JavaScrip 9月月更

MyBatis-Plus(三、增删改查)

MySQL MyBatisPlus 9月月更

Cryptocell-712安全引擎概述

Java-fenn

Java

Plato Labs推出的SeedX,公测15天570万美金净利润

EOSdreamer111

担心今年的金九银十收不到满意的offer?这份18位阿里架构师耗时60天整合的面试总结太香了!

收到请回复

Java 云计算 开源 架构 编程语言

2022年第十三届蓝桥杯Web国赛真题解析

海底烧烤店ai

前端 JavaScrip 9月月更

Github最新霸榜!号称架构师修炼之路的“葵花宝典”限时开源

了不起的程序猿

阿里巴巴 编程 程序员 架构 架构师

Sentinel哨兵机制

急需上岸的小谢

9月月更

预案三板斧的限流大法_软件工程_焦振清_InfoQ精选文章