Nginx 高并发限流模块 limit_conn_module limit_req_module

Posted by Sunday on 2018-10-22

limit_conn_module

limit_conn_module
其中$binary_remote_addr有时需要根据自己已有的log_format变量配置进行替换

1
2
3
4
5
6
7
8
9
10
11
12
http {
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
limit_conn_log_level error;
limit_conn_status 503;
...
server {
...
location /download/ {
limit_conn perip 1; # 限制每个IP只能发起1个连接
limt_rate 100k; # 限速为100kb/秒
}

limit_req_module

ngx_http_limit_req_module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#limit_req_zone $server_name zone=perserver:10m rate=10r/s; 
limit_req_zone $request_uri zone=by_uri:10m rate=30r/m; #每2秒一个请求
#rate=2r/m;每30秒一个请求

server {
listen 80;

location /by-uri/burst0.html {
limit_req zone=by_uri;
}

location /by-uri/burst5.html {
limit_req zone=by_uri burst=5;
}

location /by-uri/burst50.html {
limit_req zone=by_uri burst=5 nodelay;
}
}

10个并发请求测试:

  • 拒绝的链接有多少?
  • 接受的链接有多少?

burst0.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@node1 ~]# siege -b -r 1 -c 10 http://static.sundayle.com/by-uri/burst0.html
** SIEGE 4.0.2
** Preparing 10 concurrent users for battle.
The server is now under siege...
HTTP/1.1 200 0.02 secs: 14 bytes ==> GET /by-uri/burst0.html
HTTP/1.1 503 0.01 secs: 206 bytes ==> GET /by-uri/burst0.html
HTTP/1.1 503 0.02 secs: 206 bytes ==> GET /by-uri/burst0.html
HTTP/1.1 503 0.02 secs: 206 bytes ==> GET /by-uri/burst0.html
HTTP/1.1 503 0.02 secs: 206 bytes ==> GET /by-uri/burst0.html
HTTP/1.1 503 0.02 secs: 206 bytes ==> GET /by-uri/burst0.html
HTTP/1.1 503 0.01 secs: 206 bytes ==> GET /by-uri/burst0.html
HTTP/1.1 503 0.03 secs: 206 bytes ==> GET /by-uri/burst0.html
HTTP/1.1 503 0.02 secs: 206 bytes ==> GET /by-uri/burst0.html
HTTP/1.1 503 0.03 secs: 206 bytes ==> GET /by-uri/burst0.html

Transactions: 1 hits
Availability: 10.00 %
Elapsed time: 0.03 secs
Data transferred: 0.00 MB
Response time: 0.20 secs
Transaction rate: 33.33 trans/sec
Throughput: 0.06 MB/sec
Concurrency: 6.67
Successful transactions: 1
Failed transactions: 9
Longest transaction: 0.03
Shortest transaction: 0.01

30r/m表示每2秒允许一个新请求。这10个请求中有1个接受,9个被拒绝。

burst5.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@node1 ~]# siege -b -r 1 -c 10 http://static.sundayle.com/by-uri/burst5.html
** SIEGE 4.0.2
** Preparing 10 concurrent users for battle.
The server is now under siege...
HTTP/1.1 200 0.06 secs: 14 bytes ==> GET /by-uri/burst5.html
HTTP/1.1 503 0.14 secs: 206 bytes ==> GET /by-uri/burst5.html
HTTP/1.1 503 0.14 secs: 206 bytes ==> GET /by-uri/burst5.html
HTTP/1.1 503 0.14 secs: 206 bytes ==> GET /by-uri/burst5.html
HTTP/1.1 503 0.14 secs: 206 bytes ==> GET /by-uri/burst5.html
HTTP/1.1 200 2.02 secs: 14 bytes ==> GET /by-uri/burst5.html
HTTP/1.1 200 4.02 secs: 14 bytes ==> GET /by-uri/burst5.html
HTTP/1.1 200 6.02 secs: 14 bytes ==> GET /by-uri/burst5.html
HTTP/1.1 200 8.02 secs: 14 bytes ==> GET /by-uri/burst5.html
HTTP/1.1 200 10.02 secs: 14 bytes ==> GET /by-uri/burst5.html

Transactions: 6 hits
Availability: 60.00 %
Elapsed time: 10.02 secs
Data transferred: 0.00 MB
Response time: 5.12 secs
Transaction rate: 0.60 trans/sec
Throughput: 0.00 MB/sec
Concurrency: 3.07
Successful transactions: 6
Failed transactions: 4
Longest transaction: 10.02
Shortest transaction: 0.06

接受了5个请求,从1/10到6/10成功(其余的被拒绝)。但NGINX更新其令牌并处理接受的请求的方式在这里非常明显:输出速率上限为30r / m,相当于每2秒1个请求

第一个在0.2秒后返回。计时器在2秒后计时,并处理并返回其中一个待处理请求,总往返时间为2.02秒。 2秒后,计时器再次打勾,处理另一个待处理请求,返回的总往返时间为4.02秒。等等等等…

brust50.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@node1 ~]# siege -b -r 1 -c 10 http://static.sundayle.com/by-uri/burst50.html
** SIEGE 4.0.2
** Preparing 10 concurrent users for battle.
The server is now under siege...
HTTP/1.1 200 0.01 secs: 14 bytes ==> GET /by-uri/burst50.html
HTTP/1.1 200 0.02 secs: 14 bytes ==> GET /by-uri/burst50.html
HTTP/1.1 200 0.02 secs: 14 bytes ==> GET /by-uri/burst50.html
HTTP/1.1 200 0.02 secs: 14 bytes ==> GET /by-uri/burst50.html
HTTP/1.1 200 0.02 secs: 14 bytes ==> GET /by-uri/burst50.html
HTTP/1.1 200 0.02 secs: 14 bytes ==> GET /by-uri/burst50.html
HTTP/1.1 503 0.02 secs: 206 bytes ==> GET /by-uri/burst50.html
HTTP/1.1 503 0.02 secs: 206 bytes ==> GET /by-uri/burst50.html
HTTP/1.1 503 0.02 secs: 206 bytes ==> GET /by-uri/burst50.html
HTTP/1.1 503 0.02 secs: 206 bytes ==> GET /by-uri/burst50.html

Transactions: 6 hits
Availability: 60.00 %
Elapsed time: 0.03 secs
Data transferred: 0.00 MB
Response time: 0.03 secs
Transaction rate: 200.00 trans/sec
Throughput: 0.03 MB/sec
Concurrency: 6.33
Successful transactions: 6
Failed transactions: 4
Longest transaction: 0.02
Shortest transaction: 0.01

当爆发= 5时,我们仍然具有相同数量的状态200和503.但是现在输出速率不再严格地限制为每2秒1个请求的速率。只要有一些突发令牌可用,就会立即接受并处理任何传入请求。接受的请求不再受到任何额外的延迟。

限流白名单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
http {
geo $whiteiplist {
default 1;
127.0.0.1/32 0;
192.168.1.0/24 0;
}

map $whiteiplist $limit {
1 $binary_remote_addr;
0 "";
}

limit_conn_zone $limit zone=conn_ip:10m;
limit_req_zone $limit zone=req_ip:20m rate=10r/s;

location / {
proxy_pass http://mall.sundayle.com/;
proxy_set_header Host mall.sundayle.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;

# 若还有上一级代理添加
# 如 varish(192.168.10.0/24) --> proxy(mall.sundayle.com) --> 后端
set_real_ip_from 192.168.10.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

limit_conn conn_ip 30;
limit_rate 100k;
limit_req zone=req_ip burst=5;
}
}

需要重启下nginx才生效

限制请求数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 要限制请求数,也必须先创建一个限速池,在http段加入如下代码:
limit_req_zone $binary_remote_addr zone=one:5m;

limit_req_zone $binary_remote_addr zone=one:3m rate=1r/s;
limit_req_zone $binary_remote_addr $uri zone=two:3m rate=1r/s; # $uri:不带客户端请求参数
limit_req_zone $binary_remote_addr $request_uri zone=thre:3m rate=1r/s; # $request_uri:带客户端请求

# 限速分为全局限速和局部限速
# 对于全局限速,我们只需要在后面加上参数即可,比如每秒20个请求,rate=20r/s,即:
limit_req_zone $binary_remote_addr zone=perip:5m rate=20r/s;

# 有时候我们希望在location段调整一下链接,可以借助burst(峰值)参数
limit_req zone=one burst=50;

# 如果不希望延时,还有nodelay参数
limit_req zone=one burst=50 nodelay;

NGINX rate-limiting in a nutshell
Tengine ngx_http_limit_req_module