Nginx訪問限制模組ngx_http_limit_req_module與ngx_http_limit_conn_module(限制高併發防止DDOS攻擊)
阿新 • • 發佈:2018-12-21
Nginx訪問限制 (限制高併發防止DDOS攻擊)
ngx_http_limit_conn_module
連線頻率限制
ngx_http_limit_req_module
請求頻率限制
http協議的連線與請求
HTTP是建立在TCP基礎上,在完成HTTP請求需要先建立TCP三次握手(稱為TCP連線),在連線的基礎上在HTTP請求。
HTTP請求建立在一次TCP連線基礎上 一次TCP請求至少產生一次HTTP請求(一個連線可以有多個請求,建立一次三次握手可以傳送多個請求)
HTTP協議 | 連線關係 |
---|---|
HTTP1.0 | TCP不能複用 |
HTTP1.1 | 順序性TCP複用 |
HTTP2.0 | 多路複用TCP複用 |
Nginx請求限制配置:
# 必須在全域性定義請求限制 Syntax: limit_conn_zone key zone=name:size rate=rate; #zone的名稱大小及速率 Default: - Context: http # 引用請求限制 Syntax: limit_conn zone number [burst=number] [nodelay]; Default: - Context: http,server,location # http模組配置 limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s; > $binary_remote_addr比$remote_addr更節省位元組,是限制同一客戶端ip地址 > zone=req_zone:1m表示名稱是req_zone的記憶體區域,用來儲存訪問的頻次資訊,1m用來儲存session,1m能儲存16000個狀態 > rate限制速率為1秒最多1個IP請求,rete的值必須為整數 # location模組引用配置 limit_req zone=req_zone; # location模組引用req_zone配置,請求超過1r/s,剩下的將被延遲處理,burst=3緩衝區大小3,nodelay瞬時提供處理(burst + rate)個請求的能力,多餘的直接返回503 limit_req zone=req_zone burst=3 nodelay; http { ... limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s; server { listen 80; server_name localhost; root /usr/share/nginx/html/www; index index.html; location / { root /usr/share/nginx/html/www; index index.html; limit_req zone=req_zone; # 限制請求 #limit_req zone=req_zone burst=3 nodelay; } } } # burst : # 爆發的意思,這個配置的意思是設定一個大小為5的緩衝區,當有大量請求(爆 # 發)過來時,超過了訪問頻次限制的請求可以先放到這個緩衝區內等待, # 但是這個等待區裡的位置只有5個,超過的請求會直接報503的錯誤然後返回。 # nodelay : # 瞬時提供處理(burst + rate)個請求的能力, # 請求超過(burst + rate)的時候就會直接返回503,永遠不存在請求需要等待的情況 # 如果沒有設定nodelay,則所有請求會依次等待排隊
壓測一下請求限制效果
#安裝壓測工具 [[email protected] ~]$ yum install -y httpd-tools
場景一:burst和nodelay都不加的情況
location / { root /usr/share/nginx/html/www; index index.html; limit_req zone=req_zone; } # 使用ab測試工具,發起10個併發請求 [[email protected] ~]# ab -n 10 -c 10 http://192.168.1.17/index.html This is ApacheBench, Version 2.3 <$Revision: 1430300 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 192.168.1.17 (be patient).....done Server Software: nginx/1.14.1 Server Hostname: 192.168.1.17 Server Port: 80 Document Path: /index.html Document Length: 6 bytes Concurrency Level: 10 # 10併發個請求 Time taken for tests: 0.011 seconds Complete requests: 10 # 總共請求10次 Failed requests: 9 #失敗9次 (Connect: 0, Receive: 0, Length: 9, Exceptions: 0) Write errors: 0 Non-2xx responses: 9 Total transferred: 3700 bytes HTML transferred: 1923 bytes Requests per second: 907.94 [#/sec] (mean) Time per request: 11.014 [ms] (mean) # 11ms就壓測結束 Time per request: 1.101 [ms] (mean, across all concurrent requests) Transfer rate: 328.06 [Kbytes/sec] received >>>可以看到一共10個請求,9個請求都失敗了。且11ms就完成了壓測 # 檢視 /var/log/nginx/access.log,印證了只有一個請求成功了,其它就是都直接返回了503 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 200 6 "-" "ApacheBench/2.3" "-" 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-" 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-" 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-" 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-" 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-" 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-" 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-" 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-" 192.168.1.13 - - [14/Nov/2018:18:34:04 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
場景二:只加burst和不加nodelay的情況
1. 場景一:只加burst和不加nodelay的情況
location / {
root /usr/share/nginx/html/www;
index index.html;
limit_req zone=req_zone; # 限制請求
#limit_req zone=req_zone burst=3;
}
# 檢視當前的tcp連線數
[[email protected] ~]$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ESTABLISHED 6
[[email protected] ~]$
# 建立10個連線併發10
[[email protected] ~]$ ab -n 10 -c 5 http://192.168.1.17/index.html
....
Server Software: nginx/1.14.1
Server Hostname: 192.168.1.17
Server Port: 80
Document Path: /index.html
Document Length: 6 bytes
Concurrency Level: 10 # 10併發個請求
Time taken for tests: 0.012 seconds
Complete requests: 10 # 總共請求10次
Failed requests: 6 # 失敗了6次
Total transferred: 3250 bytes
HTML transferred: 1302 bytes
Requests per second: 3.32 [#/sec] (mean)
Time per request: 1505.007 [ms] (mean)
Time per request: 301.002 [ms] (mean, across all concurrent requests)
Transfer rate: 1.05 [Kbytes/sec] received
...
>>>> 可以看到一共10個請求,6個請求都失敗了
# ab測試第一秒時ESTABLISHED由4變為6,即建立了2個TCP連線,
# 同時TIME_WAIT=9 表示有伺服器端主動斷開了9個TCP連線,即9個請求被瞬時拒絕
[[email protected] ~]$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ESTABLISHED 6
TIME_WAIT 9
[[email protected] ~]$
# ab測試完,
# TIME_WAIT=10 表示有伺服器端主動斷開了10個TCP連線,增加的1個TIME_WAIT是因為有1個在快取佇列的請求被處理完畢了,所以斷開了連線
[[email protected] ~]$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ESTABLISHED 4
TIME_WAIT 10
[[email protected] ~]$
# 檢視 /var/log/nginx/access.log日誌
192.168.1.13 - - [14/Nov/2018:18:13:53 +0800] "GET /index.html HTTP/1.0" 200 6 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:18:13:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:18:13:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:18:13:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:18:13:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:18:13:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:18:13:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:18:13:54 +0800] "GET /index.html HTTP/1.0" 200 6 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:18:13:55 +0800] "GET /index.html HTTP/1.0" 200 6 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:18:13:56 +0800] "GET /index.html HTTP/1.0" 200 6 "-" "ApacheBench/2.3" "-"
>>>在18:13:53的時候,可以看到壓測第1秒時,成功處理了1個請求,另外有6個請求瞬間返回了503,剩下的4個請求每隔1s處理一次
>>>這是因為設定了burst=3,在伺服器接收到10個併發請求後,先處理1個請求,同時將3個請求放入burst緩衝佇列中,等待處理,
而超過(burst+1)數量的請求就被直接拋棄了,即直接拋棄了6個請求。緩衝區的剩餘3個請求,1秒執行1個。
場景三:加burst和加nodelay的情況
2. 場景二:加burst和加nodelay的情況
location / {
root /usr/share/nginx/html/www;
index index.html;
#limit_req zone=req_zone; # 限制請求
limit_req zone=req_zone burst=3 nodelay; #緩衝區大小為3,nodelay瞬時提供處理(burst + rate)個請求
}
[[email protected] ~]# ab -n 60 -c 20 http://192.168.1.17/index.html
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.1.17 (be patient).....done
Server Software: nginx/1.14.1
Server Hostname: 192.168.1.17
Server Port: 80
Document Path: /index.html
Document Length: 6 bytes
Concurrency Level: 20
Time taken for tests: 0.048 seconds
Complete requests: 10
Failed requests: 6 # 成功了4個請求(3+1)
(Connect: 0, Receive: 0, Length: 56, Exceptions: 0)
Write errors: 0
Non-2xx responses: 56
Total transferred: 3250 bytes
HTML transferred: 1302 bytes
Requests per second: 359.27 [#/sec] (mean) # 吞吐量
....
>>> 可以看到一共10個請求,失敗了6個,成功了4個,緩衝區生效了
# 檢視 /var/log/nginx/access.log日誌,可以發現在1s內,伺服器端處理了4個請求(峰值速度:burst+原來的處理速度)。對於剩下的6個請求,直接返回503
[[email protected] ~]$ tail -f /var/log/nginx/access.log
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 200 6 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 200 6 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 200 6 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 200 6 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
192.168.1.13 - - [14/Nov/2018:17:49:53 +0800] "GET /index.html HTTP/1.0" 503 213 "-" "ApacheBench/2.3" "-"
# 檢視/var/log/nginx/error.log日誌,發現有6個請求被直接拒絕了,沒有延時請求。
[[email protected] ~]$ tail -f /var/log/nginx/error.log
2018/11/14 17:49:53 [error] 20735#20735: *478 limiting requests, excess: 3.981 by zone "req_zone", client: 192.168.1.13, server: localhost, request: "GET /index.html HTTP/1.0", host: "192.168.1.17"
2018/11/14 17:49:53 [error] 20735#20735: *479 limiting requests, excess: 3.980 by zone "req_zone", client: 192.168.1.13, server: localhost, request: "GET /index.html HTTP/1.0", host: "192.168.1.17"
2018/11/14 17:49:53 [error] 20735#20735: *480 limiting requests, excess: 3.980 by zone "req_zone", client: 192.168.1.13, server: localhost, request: "GET /index.html HTTP/1.0", host: "192.168.1.17"
2018/11/14 17:49:53 [error] 20735#20735: *481 limiting requests, excess: 3.978 by zone "req_zone", client: 192.168.1.13, server: localhost, request: "GET /index.html HTTP/1.0", host: "192.168.1.17"
2018/11/14 17:49:53 [error] 20735#20735: *482 limiting requests, excess: 3.978 by zone "req_zone", client: 192.168.1.13, server: localhost, request: "GET /index.html HTTP/1.0", host: "192.168.1.17"
2018/11/14 17:49:53 [error] 20735#20735: *483 limiting requests, excess: 3.977 by zone "req_zone", client: 192.168.1.13, server: localhost, request: "GET /index.html HTTP/1.0", host: "192.168.1.17"
Nginx請求限制總結
- limit_req zone=req_zone; 超過rate處理能力範圍的,直接drop 表現為對收到的請求無延時
- limit_req zone=req_zone burst=3; 同時設定了一個大小為3的緩衝佇列,在緩衝佇列中的請求會等待慢慢處理 超過了burst緩衝佇列長度和rate處理能力的請求被直接丟棄 表現為對收到的請求有延時
- limit_req zone=req_zone burst=3 nodelay; 設定大小為5的緩衝佇列,當請求到來時,會爆發出一個峰值處理能力,對於峰值處理數量之外的請求,直接丟棄 在完成峰值請求之後,緩衝佇列不能再放入請求。如果rate=1r/s,且這段時間內沒有請求再到來,則每1s 緩衝佇列就能回覆一個緩衝請求的能力,直到回覆到能緩衝3個請求位置。
Nginx連線頻率限制配置
- 語法:
# 全域性定義連線限制
句法: limit_conn_zone key zone-name:size;
預設: -
語境: http
# 引用連線限制
句法: limit_conn zone number;
預設: -
語境: http,server,location
# 例項配置[[email protected] /etc/nginx]$ vim nginx.conf
...
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html/www;
index index.html;
location / {
root /usr/share/nginx/html/www;
index index.html;
#limit_req zone=req_zone;
#limit_req zone=req_zone burst=3 nodelay;
#同一時間只允許一個客戶端IP連線
limit_conn conn_zone 1;
}
}