限流的分类:

1)合法性验证限流:比如验证码、IP 黑名单等,这些手段可以有效的防止恶意攻击和爬虫采集;

2)容器限流:比如 Tomcat、Nginx 等限流手段,其中 Tomcat 可以设置最大线程数(maxThreads),当并发超过最大线程数会排队等待执行;而Nginx提供了两种限流手段:一是控制速率,二是控制并发连接数;

3)服务端限流:比如我们在服务器端通过限流算法实现限流。

6种具体的实现限流的手段:

1)Tomcat 使用 maxThreads来实现限流。

2)Nginx的limit_req_zone和 burst来实现速率限流。

3)Nginx的limit_conn_zone和 limit_conn两个指令控制并发连接的总数。

4)时间窗口算法借助 Redis的有序集合可以实现。

5)漏桶算法可以使用Redis-Cell来实现。

6)令牌算法可以解决Google的guava包来实现。

需要注意的是借助Redis实现的限流方案可用于分布式系统,而guava实现的限流只能应用于单机环境。如果你觉得服务器端限流麻烦,可以在不改任何代码的情况下直接使用容器限流(Nginx或Tomcat),但前提是能满足项目中的业务需求。

Tomcat限流

Tomcat 8.5 版本的最大线程数在 conf/server.xml 配置中,如下所示:

其中 maxThreads 就是 Tomcat 的最大线程数,当请求的并发大于此值(maxThreads)时,请求就会排队执行,这样就完成了限流的目的。

注意:

maxThreads 的值可以适当的调大一些,Tomcat默认为 150(Tomcat 版本 8.5),但这个值也不是越大越好,要看具体的服务器配置,需要注意的是每开启一个线程需要耗用 1MB 的 JVM 内存空间用于作为线程栈之用,并且线程越多 GC 的负担也越重。

最后需要注意一下,操作系统对于进程中的线程数有一定的限制,Windows 每个进程中的线程数不允许超过 2000,Linux 每个进程中的线程数不允许超过 1000。

Nginx 限流

Nginx 提供了两种限流方法:一种是控制速率,另一种是控制并发连接数。

控制速率

我们需要使用 limit_req_zone 用来限制单位时间内的请求数,即速率限制,示例配置如下:

上面配置的意思是,限制单个IP访问的速度为 2r/s,因为Nginx的限流统计是基于毫秒的,我们设置的速度是 2r/s,转换一下就是500毫秒内单个IP只允许通过1个请求,从501ms开始才允许通过第2个请求。

我们使用单IP在10ms内发并发送了6个请求的执行结果如下图:

从以上结果可以看出它的执行符合我们的预期,只有 1 个执行成功了,其他的 5 个被拒绝了(第 2 个在 501ms 才会被正常执行)。

控制速率优化版

上面的速率控制虽然很精准但是在生产环境未免太苛刻了,实际情况下我们应该控制一个IP单位总时间内的总访问次数,而不是像上面那样精确到毫秒,我们可以使用 burst 关键字开启此设置,配置如下:

burst=4意思是每个IP最多允许4个突发请求,单个IP在10ms内发送6次请求的结果如下图:

从以上结果可以看出,有1个请求被立即处理了,4个请求被放到 burst 队列里排队执行了,另外1个请求被拒绝了。

控制并发数

利用 limit_conn_zone 和 limit_conn 两个指令即可控制并发数,示例配置如下:

其中 limit_conn perip 10 表示限制单个 IP 同时最多能持有 10 个连接;limit_conn perserver 100 表示 server 同时能处理并发连接的总数为 100 个。

注意:只有当 request header 被后端处理后,这个连接才进行计数。

好了,今天先介绍这三种方式,服务端限流的三种方案下回讲。

 原文地址:开发者导航 · 你想要的,我全都有!

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐