nginx限制客户端请求数+iptables限制TCP链接和频率来防止DDOS

DDOS的特色是分布式,针对带宽和服务×××,即四层流量×××和七层应用×××。对于七层的应用×××,若是前端是Nginx,主要使用nginx的http_limit_conn和http_limit_req模块来防护,经过限制链接数和请求数能相对有效的防护CC×××。html

* ngx_http_limit_req_module:限制单个IP单位时间内的请求数,即速率限制,该模块默认已经安装
* ngx_http_limit_conn_module:限制单个IP同一时间链接数,即并发链接数限制

一个TCP链接能够产生多个请求,例如,一个页面上有不少图片,对客户端来讲只须要发送这个页面的一次请求,而每一个图片实际对应的就是一个链接,因此实际应用中对请求作限制比对链接作限制的效果更好。前端


ngx_http_limit_req_module:限制每秒请求数node

  • ngx_http_limit_req_module模块经过漏桶原理来限制单位时间内的请求数,一旦单位时间内请求数超过限制,就会返回503错误。
  • ngx_http_limit_req_module模块有2部分:
* 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;
    说明:一、$binary_remote_addr:是$remote_addr(客户端IP)的二进制格式,固定占用4个字节,而$remote_addr按照字符串存储,占用7-15个字节,用$binary_remote_addr能够节省空间。这样1M的内存能够保存大约1万6千个64字节的记录。
    二、zone=:区域名称,可自定义,这里写的是two,分配内存空间大小为100m,,用来存储会话(二进制远程地址),若是限制域的存储空间耗尽了,对于后续全部请求,服务器都会返回 503 (Service Temporarily Unavailable)错误。
    三、rate=:平均处理的请求数,这里定义的是每秒不能超过每秒50次。也能够设置为每分钟处理请求数(r/m),其值必须是整数,
  • server, location段:
  • 一、limit_req zone
    语法: limit_req zone=name [burst=number] [nodelay];
    实例:limit_req zone=two burst=20 nodelay;
    说明:一、zone=:和http字段中limit_req_zone的zone定义必须一致
    二、burst=:能够理解为缓冲队列
    三、nodelay:对用户发起的请求不作延迟处理,而是当即处理。好比上面定义了rate=20r/s,即每秒钟只处理20个请求。若是同一时刻有22个请求过,若设置了nodelay,则会马上处理这22个请求。若没设置nodelay,则会严格执行rate=20r/s的配置,即只处理20个请求,而后下一秒钟再处理另外2个请求。直观的看就是页面数据卡了,过了一秒后才加载出来。

例如:nginx

[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拒绝的。c++

  • 二、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级别。web

  • 三、limit_req_status
    语法: limit_req_status code;
    默认值: limit_req_status 503;
    配置段: http, server, location
    该指令在1.3.15版本引入。设置拒绝请求的响应状态码。

ngx_http_limit_conn_module:限制IP链接数apache

ngx_http_limit_conn_module的模块也有2部分:vim

* 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。链接数限制不是全部的链接都计算在内;只有那些已请求该服务器并当前正在处理的请求(请求头已充分阅读的)。windows

  • server, location段:
  • 一、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=perip:100m;
    limit_conn_zone  $server_name  zone=perserver:100m;
            ......
            server {
                       ......
                                 listen 80;
                                 ......
                                 limit_conn perip 50;;     #同一个IP限制连接20个
                                 limit_conn perserver 20;;   #同一主机名连接限制在100个
                                 ......
                                 }
        }

*二、 limit_conn_log_level
语法: limit_conn_log_level info | notice | warn | error;
默认值: limit_conn_log_level error;
使用环境: http, server, location
设置触发最大限制后记录日志的级别,默认为error级别,该指令在 0.8.18版后新增

*三、 limit_conn_status
语法: limit_conn_status code;
默认值: limit_conn_status 503;
使用环境: http, server, location
当超出最大同时链接数的时候,对于新增链接返回的错误代码,默认503. 该指令在 1.3.15版本后新增,

*四、 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.
相关文章
相关标签/搜索