nginx限制客戶端請求數+iptables限制TCP連接和頻率來防止DDOS

DDOS的特點是分佈式,針對帶寬和服務×××,即四層流量×××和七層應用×××。對於七層的應用×××,如果前端是Nginx,主要使用nginx的http_limit_conn和http_limit_req模塊來防禦,通過限制連接數和請求數能相對有效的防禦CC×××。

* ngx_http_limit_req_module:限制單個IP單位時間內的請求數,即速率限制,該模塊默認已經安裝
* ngx_http_limit_conn_module:限制單個IP同一時間連接數,即併發連接數限制

一個TCP連接可以產生多個請求,例如,一個頁面上有很多圖片,對客戶端來說只需要發送這個頁面的一次請求,而每個圖片實際對應的就是一個連接,所以實際應用中對請求做限制比對連接做限制的效果更好。


ngx_http_limit_req_module:限制每秒請求數

  • ngx_http_limit_req_module模塊通過漏桶原理來限制單位時間內的請求數,一旦單位時間內請求數超過限制,就會返回503錯誤。
  • ngx_http_limit_req_module模塊有2部分:
* http字段中定義觸發條件,可以有多個條件;
* http、server、location段中定義達到觸發條件時nginx所要執行的動作。
  • http段:
    語法:limit_req_zone $variable zone=name:size rate=rate;
    實例:limit_req_zone $binary_remote_addr zone=two:100m rate=50r/s;
    說明:1、$binary_remote_addr:是$remote_addr(客戶端IP)的二進制格式,固定佔用4個字節,而$remote_addr按照字符串存儲,佔用7-15個字節,用$binary_remote_addr可以節省空間。這樣1M的內存可以保存大約1萬6千個64字節的記錄。
    2、zone=:區域名稱,可自定義,這裏寫的是two,分配內存空間大小爲100m,,用來存儲會話(二進制遠程地址),如果限制域的存儲空間耗盡了,對於後續所有請求,服務器都會返回 503 (Service Temporarily Unavailable)錯誤。
    3、rate=:平均處理的請求數,這裏定義的是每秒不能超過每秒50次。也可以設置爲每分鐘處理請求數(r/m),其值必須是整數,
  • http, server, location段:
  • 1、limit_req zone
    語法: limit_req zone=name [burst=number] [nodelay];
    實例:limit_req zone=two burst=20 nodelay;
    說明:1、zone=:和http字段中limit_req_zone的zone定義必須一致
    2、burst=:可以理解爲緩衝隊列
    3、nodelay:對用戶發起的請求不做延遲處理,而是立即處理。比如上面定義了rate=20r/s,即每秒鐘只處理20個請求。如果同一時刻有22個請求過,若設置了nodelay,則會立刻處理這22個請求。若沒設置nodelay,則會嚴格執行rate=20r/s的配置,即只處理20個請求,然後下一秒鐘再處理另外2個請求。直觀的看就是頁面數據卡了,過了一秒後才加載出來。

例如:

[root@localhost sbin]# vim /app/OpenResty/nginx/conf/nginx.conf
......
http {
        ......
            limit_req_zone $binary_remote_addr zone=two:100m rate=50r/s;
            ......
            server {
                       ......
                                 listen 80;
                                 ......
                                 limit_req zone=two burst=20 nodelay;
                                 ......
                                 }
        }                        
  • 對限流起作用的配置就是rate=50r/s和burst=20這兩個配置,假如同一秒有55個請求到達nginx,其中50個請求被處理,另外的5個請求被放到burst緩衝隊列裏,由於配置了nodelay,第51-55個請求依然會被處理,但是會佔用burst緩衝隊列的5個長度,如果下一秒沒有新的請求過來,這5個長度的空間會被釋放,否則會繼續佔用burst緩衝隊列5個長度,如果後面每秒請求都超過50個,那麼多餘的請求雖然會被處理但是會佔用burst緩衝隊列長度,直到達到設定的burst=20,後面的每秒第51個請求開始會被nginx拒絕,並返回503錯誤,被拒絕的請求在nginx的日誌中可以看到被那個zone拒絕的。

  • 2、limit_req_log_level
    語法: limit_req_log_level info | notice | warn | error;
    默認值: limit_req_log_level error;
    配置段: http, server, location
    設置日誌級別,當服務器因爲頻率過高拒絕或者延遲處理請求時可以記下相應級別的日誌。 延遲記錄的日誌級別比拒絕的低一個級別; 如果設置“limit_req_log_level notice”, 延遲的日誌就是info級別。

  • 3、limit_req_status
    語法: limit_req_status code;
    默認值: limit_req_status 503;
    配置段: http, server, location
    該指令在1.3.15版本引入。設置拒絕請求的響應狀態碼。

ngx_http_limit_conn_module:限制IP連接數

ngx_http_limit_conn_module的模塊也有2部分:

* http字段中定義觸發條件,可以有多個條件;
* http、server、location段中定義達到觸發條件時nginx所要執行的動作。
  • http段:
    語法:limit_conn_zone key zone=name:memory_max_size;
    實例:limit_conn_zone $binary_remote_addr zone=one:10m;
    說明:limit_conn_zone模塊只能配置在http字段中進行定義,該指令描述會話狀態存儲區域。主要用來定義變量、zone名稱、共享內存大小,鍵的狀態中保存了當前連接數,鍵的值可以是特定變量的任何非空值(空值不會被考慮)。size 定義各個鍵共享內存空間大小,如果共享內存空間被耗盡,服務器將會對後續所有的請求返回 503 (Service Temporarily Unavailable) 錯誤。從Nginx 1.1.8版本後limit_conn升級爲limit_conn_zone。連接數限制不是所有的連接都計算在內;只有那些已請求該服務器並當前正在處理的請求(請求頭已充分閱讀的)。

  • http, server, location段:
  • 1、limit_conn one
    語法:limit_conn one conn_max_num;
    實例:limit_conn one 20;
    說明:該指令指定每個給定鍵值的最大同時連接數,當超過這個數字時返回503(Service )錯誤。如(同一IP同一時間只允許有20個連接)。
[root@localhost sbin]# vim /app/OpenResty/nginx/conf/nginx.conf
......
http {
        ......
            limit_conn_zone  $binary_remote_addr  zone=one:10m;
            ......
            server {
                       ......
                                 listen 80;
                                 ......
                                 limit_conn one 20;
                                 ......
                                 }
        }   

還可以疊加使用,同時限制訪問的虛擬主機:

[root@localhost sbin]# vim /app/OpenResty/nginx/conf/nginx.conf
......
http {
        ......
            limit_conn_zone  $binary_remote_addr  zone=one:10m;
            limit_conn_zone $server_name zone=two:10m; 
            ......
            server {
                       ......
                                 listen 80;
                                 ......
                                 limit_conn one 20;     #同一個IP限制鏈接20個
                                 limit_conn two 100;   #同一主機名鏈接限制在100個
                                 ......
                                 }
        }   

*2、 limit_conn_log_level
語法: limit_conn_log_level info | notice | warn | error;
默認值: limit_conn_log_level error;
使用環境: http, server, location
設置觸發最大限制後記錄日誌的級別,默認爲error級別,該指令在 0.8.18版後新增

*3、 limit_conn_status
語法: limit_conn_status code;
默認值: limit_conn_status 503;
使用環境: http, server, location
當超出最大同時連接數的時候,對於新增連接返回的錯誤代碼,默認503. 該指令在 1.3.15版本後新增,

*4、 limit_rate
語法:limit_rate rate
默認值:0
實例:limit_rate 200k;
配置段:http, server, location, if in location
對每個連接的速率限制。參數rate的單位是字節/秒,設置爲0將關閉限速。 按連接限速而不是按IP限制,因此如果某個客戶端同時開啓了兩個連接,那麼客戶端的整體速率是這條指令設置值的2倍。


白名單設置

http_limit_conn和http_limit_req模塊限制了單ip單位時間內的併發和請求數,如前端如果有做LVS或反代,對於後端的ningx來說過來的請求都是lvs或者反代的IP,而我們後端啓用了該模塊功能,那不是非常多503錯誤了?這樣的話,就需要geo和map模塊設置白名單:

    geo $whiteiplist  {
        default 1;
        10.15.43.18 0;
    }
    map $whiteiplist  $limit {
        1 $binary_remote_addr;
        0 "";
    }

geo模塊定義了一個默認值default 1的變量$whiteiplist,當ip在白名單中,變量whiteiplist的值爲0(10.15.43.18 0),反之爲1
如果在白名單中--> whiteiplist=0 --> $limit="" --> 不會存儲到zone對應的內存共享會話狀態中 --> 不受限制
反之,不在白名單中 --> whiteiplist=1 --> $limit=二進制遠程地址 -->存儲進zone對應的內存共享會話狀態中 --> 受到限制

iptables設置

單個IP在60秒內只允許新建20個連接訪問web的80端口
iptables -I  INPUT -i eth1 -p tcp -m tcp –dport 80 -m state –state NEW -m recent –update –seconds 60 –hitcount 20 –name DEFAULT –rsource -j DROP
iptables -I  INPUT -i eth1 -p tcp -m tcp –dport 80 -m state –state NEW -m recent –set –name DEFAULT –rsource

單個IP的最大併發連接數爲20
iptables  -I INPUT -p tcp –dport 80 -m connlimit  –connlimit-above 20 -j REJECT  

每個IP最多20個初始連接
iptables -I  INPUT -p tcp –syn -m connlimit –connlimit-above 20 -j DROP

測試

使用ab命令來模擬CC×××,http_limit_conn和http_limit_req模塊要分開測試,同時注意http_limit_conn模塊只統計正在被處理的請求(這些請求的頭信息已被完全讀入)所在的連接。如果請求已經處理完,連接沒有被關閉時,是不會被統計的。這時用netstat看到連接數可以超過限定的數量,不會被阻止。

http {
    ......
    geo $whiteiplist  {
        default 1;
        10.15.43.18 0;
    }
    map $whiteiplist  $limit {
        1 $binary_remote_addr;
        0 "";
    }
    limit_req_zone $binary_remote_addr zone=one:100m rate=50r/s;
    limit_conn_zone $binary_remote_addr zone=two:10m;
    limit_conn_zone $server_name zone=three:10m;    
......  
   server {
        listen       80;
        server_name  192.168.100.127;
        ......
        server_tokens off;
        limit_req zone=one burst=20 nodelay;
        limit_req_log_level error;
        limit_req_status 503;
        limit_conn two 20;
        limit_conn three 3;
        limit_conn_log_level error;
        limit_conn_status 503;
        limit_rate 200k;
        ......

        location / {
            root   html;
            index  index.html index.htm;
        }
        ......
}   
  • Web網站壓力測試工具ab(apache benchmark)

ab是針對apache的性能測試工具,在APACHE的bin目錄下,也可以只安裝ab工具。

[root@localhost ~]# yum install -y httpd-tools
[root@localhost ~]# ab -V
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/
[root@localhost ~]# ab -v
ab: option requires an argument -- v
ab: wrong number of arguments
Usage: ab [options] [http[s]://]hostname[:port]/path
Options are:
    -n requests     Number of requests to perform       #在測試會話中所執行的請求次數。默認時,僅執行一個請求
    -c concurrency  Number of multiple requests to make at a time        #一次產生的請求個數,即併發數。默認是一次一個
    -t timelimit    Seconds to max. to spend on benchmarking    #測試所進行的最大秒數。其內部隱含值是-n 50000。它可以使對服務器的測試限制在一個固定的總時間以內。默認時,沒有時間限制。
                    This implies -n 50000
    -s timeout      Seconds to max. wait for each response
                    Default is 30 seconds
    -b windowsize   Size of TCP send/receive buffer, in bytes
    -B address      Address to bind to when making outgoing connections
    -p postfile     File containing data to POST. Remember also to set -T           #包含了需要POST的數據的文件. 
    -u putfile      File containing data to PUT. Remember also to set -T
    -T content-type Content-type header to use for POST/PUT data, eg.              #POST數據所使用的Content-type頭信息。
                    'application/x-www-form-urlencoded'
                    Default is 'text/plain'
    -v verbosity    How much troubleshooting info to print   #設置顯示信息的詳細程度 - 4或更大值會顯示頭信息, 3或更大值可以顯示響應代碼(404, 200等), 2或更大值可以顯示警告和其他信息。 -V 顯示版本號並退出。
    -w              Print out results in HTML tables         #以HTML表的格式輸出結果。默認時,它是白色背景的兩列寬度的一張表。
    -i              Use HEAD instead of GET              #執行HEAD請求,而不是GET
    -x attributes   String to insert as table attributes
    -y attributes   String to insert as tr attributes
    -z attributes   String to insert as td or th attributes
    -C attribute    Add cookie, eg. 'Apache=1234'. (repeatable)      #-C cookie-name=value 對請求附加一個Cookie:行。 其典型形式是name=value的一個參數對。此參數可以重複。
    -H attribute    Add Arbitrary header line, eg. 'Accept-Encoding: gzip'
                    Inserted after all normal header lines. (repeatable)
    -A attribute    Add Basic WWW Authentication, the attributes
                    are a colon separated username and password.
    -P attribute    Add Basic Proxy Authentication, the attributes               
                    are a colon separated username and password.       #-P proxy-auth-username:password 對一箇中轉代理提供BASIC認證信任。用戶名和密碼由一個:隔開,並以base64編碼形式發送。無論服務器是否需要(即, 是否發送了401認證需求代碼),此字符串都會被髮送。
    -X proxy:port   Proxyserver and port number to use
    -V              Print version number and exit
    -k              Use HTTP KeepAlive feature
    -d              Do not show percentiles served table.
    -S              Do not show confidence estimators and warnings.
    -q              Do not show progress when doing more than 150 requests
    -g filename     Output collected data to gnuplot format file.
    -e filename     Output CSV file with percentages served
    -r              Don't exit on socket receive errors.
    -h              Display usage information (this message)
    -Z ciphersuite  Specify SSL/TLS cipher suite (See openssl ciphers)
    -f protocol     Specify SSL/TLS protocol
                    (SSL3, TLS1, TLS1.1, TLS1.2 or ALL)
root@localhost ~]# ab -n1000 -c10 http://192.168.100.127/index.html      #同時處理10個請求,連續1000次
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.100.127 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software:        openresty             #測試的Web服務器軟件名稱
Server Hostname:        192.168.100.127      #服務器主機名
Server Port:            80

Document Path:          /index.html
Document Length:        6110 bytes

Concurrency Level:      10     #併發數
Time taken for tests:   0.255 seconds          #整個測試持續的時間
Complete requests:      1000          #完成的請求數量
Failed requests:        967                 #失敗的請求數量
   (Connect: 0, Receive: 0, Length: 967, Exceptions: 0)
Write errors:           0
Non-2xx responses:      967
Total transferred:      917130 bytes                 #整個場景中的網絡傳輸量
HTML transferred:       724777 bytes           #整個場景中的HTML內容傳輸量
Requests per second:    3917.94 [#/sec] (mean)           #吞吐率,重要指標之一,相當於 LR 中的 每秒事務數 ,後面括號中的 mean 表示這是一個平均值
Time per request:       2.552 [ms] (mean)    #用戶平均請求等待時間,重要指標之二,相當於 LR 中的 平均事務響應時間
Time per request:       0.255 [ms] (mean, across all concurrent requests)    #服務器平均請求處理時間,重要指標之三
Transfer rate:          3509.05 [Kbytes/sec] received         #平均每秒網絡上的流量,可以幫助排除是否存在網絡流量過大導致響應時間延長的問題

Connection Times (ms)             #網絡上消耗的時間的分解
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     1    2   0.7      2       5
Waiting:        1    2   0.7      2       5
Total:          1    2   0.7      2       5

Percentage of the requests served within a certain time (ms)              #每個請求處理時間的分佈情況
  50%      2
  66%      3
  75%      3
  80%      3
  90%      3
  95%      5
  98%      5
  99%      5
 100%      5 (longest request)
 #整個場景中所有請求的響應情況。在場景中每個請求都有一個響應時間,其中50%的用戶響應時間小於2 毫秒,66% 的用戶響應時間小於3毫秒,最大的響應時間小於5 毫秒
[root@localhost ~]# 
  1. 吞吐率(Requests per second)
    概念:服務器併發處理能力的量化描述,單位是reqs/s,指的是某個併發用戶數下單位時間內處理的請求數。某個併發用戶數下單位時間內能處理的最大請求數,稱之爲最大吞吐率。
    計算公式:總請求數 / 處理完成這些請求數所花費的時間,即
    Request per second = Complete requests / Time taken for tests

  2. 併發連接數(The number of concurrent connections)
    概念:某個時刻服務器所接受的請求數目,簡單的講,就是一個會話。

  3. 併發用戶數(The number of concurrent users,Concurrency Level)
    概念:要注意區分這個概念和併發連接數之間的區別,一個用戶可能同時會產生多個會話,也即連接數。

  4. 用戶平均請求等待時間(Time per request)
    計算公式:處理完成所有請求數所花費的時間/ (總請求數 / 併發用戶數),即
    Time per request = Time taken for tests /( Complete requests / Concurrency Level)

  5. 服務器平均請求等待時間(Time per request: across all concurrent requests)
    計算公式:處理完成所有請求數所花費的時間 / 總請求數,即
    Time taken for / testsComplete requests
    可以看到,它是吞吐率的倒數。
    同時,它也=用戶平均請求等待時間/併發用戶數,即
    Time per request / Concurrency Level

Webbench是知名的網站壓力測試工具,它是由Lionbridge公司開發。它能測試處在相同硬件上,不同服務的性能以及不同硬件上同一個服務的運行狀況。能夠統計每秒鐘相應請求數和每秒鐘傳輸數據量。webbench既能測試靜態頁面,還能對動態頁面(ASP,PHP,JAVA,CGI)進 行測試。還支持對含有SSL的安全網站進行靜態或動態的性能測試。最多可以模擬3萬個併發連接去測試網站的負載能力。
官網:http://home.tiscali.cz/~cz210552/webbench.html
webbench會fork出多個子進程,每個子進程都循環做web訪問測試。子進程把訪問的結果通過pipe告訴父進程,父進程做最終的統計結果

[root@localhost soft]# yum install ctags wget make apr* autoconf automake gcc gcc-c++
[root@localhost soft]# wget http://home.tiscali.cz/cz210552/distfiles/webbench-1.5.tar.gz
[root@localhost soft]# tar -zxvf webbench-1.5.tar.gz
[root@localhost soft]# cd webbench-1.5
[root@localhost webbench-1.5]# make
[root@localhost webbench-1.5]# make install  #這步可能提示/usr/local/man不存在,如果存在檢查權限
[root@localhost webbench-1.5]# which webbench
/usr/local/bin/webbench
[root@localhost webbench-1.5]# webbench --help
webbench [option]... URL
  -f|--force               Don't wait for reply from server.     #不需要等待服務器相應
  -r|--reload              Send reload request - Pragma: no-cache.    #不發送重新加載請求
  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.    #運行測試持續時間,單位秒
  -p|--proxy <server:port> Use proxy server for request.   #使用代理服務器發送請求
  -c|--clients <n>         Run <n> HTTP clients at once. Default one.   #執行併發客戶端數量,默認1個
  -9|--http09              Use HTTP/0.9 style requests.    #使用http/0.9
  -1|--http10              Use HTTP/1.0 protocol.       #使用HTTP/1.0協議
  -2|--http11              Use HTTP/1.1 protocol.       
  --get                    Use GET request method.     
  --head                   Use HEAD request method.
  --options                Use OPTIONS request method.
  --trace                  Use TRACE request method.
  -?|-h|--help             This information.
  -V|--version             Display program version.
[root@localhost webbench-1.5]# webbench -c 10 -t 30 http://192.168.100.127
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Invalid URL syntax - hostname don't ends with '/'.
[root@localhost webbench-1.5]# webbench -c 10 -t 30 http://192.168.100.127/
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://192.168.100.127/
10 clients, running 30 sec.

Speed=245980 pages/min, 26000094 bytes/sec.    #每秒鐘響應請求數:245980 pages/min,每秒鐘傳輸數據量26000094 bytes/sec.
Requests: 122990 susceed, 0 failed.       #122990次返回成功,0次返回失敗
[root@localhost soft]# cat webbench.sh 
#!/bin/bash
export LANG="en_US.UTF-8"
#export LANG="zh_CN.UTF8"
source /etc/rc.d/init.d/functions
[ -f /etc/profile ] && . /etc/profile
[ -f ~/.bash_profile ] && . ~/.bash_profile
for n in `seq 5 5 50`;do 
   echo -n $n " " 
   webbench -c $n -t 60 http://192.168.100.127/ 2>/dev/null | grep Speed | awk '{print $1}' | awk -F= '{print $2}' 
   echo 
done
[root@localhost soft]#
  • webbench的優點:
    1.部署簡單,適用於小型網站壓力測試,(最多可模擬3萬併發);
    2.它具有靜態頁面測試能力也支持動態頁面(ASP,PHP,JAVA,CGI)進行測試能力;
    3.支持對含有SSL的安全網站如電子商務網站進行動態或靜態性能測試;

  • webbench的缺點:
    1.不適合中大型網站測試;
    2.其併發採用多進程實現並非線程,長時間其會大量佔用內存與CPU,所以一般長時間的壓力測試不推薦使用webbench.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章