关于Nginx的连接限制心得分析

HTTP/1.0 & 1.1 & 2.0

HTTP/1.0中,一个http请求收到服务器响应后,会断开对应的TCP连接。这样每次请求,都需要重新建立TCP连接,这样一直重复建立和断开的过程,比较耗时。所以为了充分利用TCP连接,可以设置头字段Connection:keep-alive,这样http请求完成后,就不会断开当前的TCP连接,后续的http请求可以使用当前TCP连接进行通信。

HTTP/1.1将Connection写入了标准,默认值为keep-alive。除非强制设置为Connection:close,才会在请求后断开TCP连接。

Keep-alive:客户端和服务端在建立连接并完成Request后并不会立即断开TCP连接,而是在下次Request来临时复用这次TCP连接。

问题就来了,一个TCP连接可以发多少个HTTP请求呢?只要能明白上文所说的话,其实这个问题已经有了答案,如果维持连接,一个TCP连接是可以发送多个HTTP请求的。

那么,一个TCP连接中HTTP请求发送可以一起发送么(比如一起发三个请求,再三个响应一起接收)?

HTTP/1.1存在一个问题,单个TCP连接在同一时刻只能处理一个请求,意思是说:两个请求的生命周期不能重叠,任意两个HTTP请求从开始到结束的时间在同一个TCP连接里不能重叠。虽然HTTP/1.1规范中规定了Pipelining来试图解决这个问题,但是这个功能在浏览器中默认是关闭的。

因此,我们得到的结论是:在现代浏览器中,每次打开网页会打开一个TCP连接,在一个TCP连接生命周期内,所有请求(静态文件、接口请求)会被按顺序请求,直至完结。

既然如此,那拓展到客户端的角度来说,现代浏览器对同一Host建立TCP连接到数量有没有限制?、

假设我们还处在HTTP/1.1时代,那个时候没有多路传输,当浏览器拿到一个有几十张图片的网页该怎么办呢?肯定不能只开一个TCP连接顺序下载,那样用户肯定等的很难受,但是如果每个图片都开一个TCP连接发HTTP请求,那电脑或者服务器都可能受不了,要是有1000张图片的话总不能开1000个TCP连接吧,你的电脑同意NAT也不一定会同意。

所以答案是:。Chrome最多允许对同一个Host建立六个TCP连接。不同的浏览器有一些区别。


nginx 限制请求数

通过上文,我们知道现代浏览器支持对同一个Host建立复数个TCP连接,每个TCP连接按照其生命周期对服务器发送请求。那么我们该如何限制过多的请求呢?

首先,如果服务器配置允许,网站应该支持尽可能多的并发(即支持尽可能多的用户同时访问)。假设网站某一个存在K个用户,以人类的操作习惯每次打开一个浏览器,浏览器会打开V个TCP连接,即每人每次浏览会给网站带来K×V个TCP连接。

为了用户的体验着想,我们当然不希望用户看到的是从上到下慢慢加载,所以我们不会去限制TCP连接数量,而是限制HTTP连接数

Nginx自带的limit_conn_module模块(TCP连接频率限制模块)和limit_req_mudule模块(HTTP请求频率限制模块)支持对连接频率以及请求频率、来源进行限制,通常可可以用来防止DDOS攻击。

语法(命令 <参数> [可选参数]) 范围 说明
limit_conn_zone <标识> zone=<空间名>:<空间大小> http 用于声明一个存储空间
limit_conn <空间名> <并发限制数>; http、server、location 用于限制某个存储空间的并发数量
imit_conn_log_level <日志等级>; http、server、location 当达到最大限制连接数后, 记录日志的等级
limit_conn_status <状态码>; http、server、location 当超过限制后,返回的响应状态码,默认是503
limit_req_zone key zone=<空间名>:<空间大小> rate=<每秒请求数>; http 用于声明一个存储空间
limit_req zone=<空间名> [burst=<队列数>] [nodelay]; http、server、location 用于限制某个存储空间的并发数量

示例如下:

http {
    limit_req_zone $binary_remote_addr zone=req_zone:10m rate=10r/s;
}
server {
    location / {
        ...
        index  index.html;
        limit_req zone=req_zone burst=100 nodelay;
    }
}
zone:one:10m 表示一个内存区域大小为10m,并且设定了名称为one,内存区域10m,大概16万个session.
rate=5r/s 表示请求的速率是1秒5个请求,当单位设置成60r/m时,并不能达到限速1分钟60次的效果,它等同于1r/s。   
$binary_remote_addr 表示按照远程的ip地址来限制,如果换成$host等其他参数则同理,当此nginx前方还存在代理时,需进行处理
——————
zone=req_zone 表示这个参数对应的全局设置就是req_zone的那个内存区域
burst=100 表示请求队列的长度。
nodelay 表示不延时,配置中一秒限制处理100+10个请求。比如rate=5r/s,burst=10 那么来了15个请求,能一次搞定,否则,就是此秒只能搞定5个请求,第6-10个等待,第11个及其更多被返回503。一般都是不延期的设置。

上文提到,某一刻存在K×V个TCP连接,即K×V个HTTP请求,也就是说我们限制每秒处理量为K×V≤110

对于检索

现有假设某网站的一个检索应用程序,打开检索时,需要同时请求以下数据

  • 最新消息
  • 热门搜索
  • 搜索建议词
  • 搜索的结果

同时,为了保证检索效果,还会带来以下请求

  • 筛选网站名称
  • 静态图片资源
  • 静态文字资源
  • ...(更多)

示例如下:

http {
    limit_conn_zone $binary_remote_addr zone=conn_zone:10m;               # new
    limit_req_zone $binary_remote_addr zone=req_zone:10m rate=10r/s;
}
server {
    set $limit 0;
    if ( $request_uri ~ *(something rulse should be here)* ){
        set $limit 1;
    }
    location / {
        ...
        index  index.html;
        limit_req zone=req_zone burst=100 nodelay;
        if ($limit = 1) {
            limit_conn conn_zone 1;
        }
    }
}
set 设置某个变量
request_uri 如果客户端完整URI匹配到一些关键词,则设置限制变量为1
limit_conn 引用全局中的连接限制zone,并设置同一时刻只允许一个客户端连接

猜你喜欢

转载自www.cnblogs.com/fottencity/p/13375272.html