轩辕阁 发表于 2018-11-10 09:34:23

Nginx学习(四)Nginx限制整合


[*]  nginx限制连接数ngx_http_limit_conn_module模块
  1. 前言
  我们经常会遇到这种情况,服务器流量异常,负载过大等等。对于大流量恶意的***访问,会带来带宽的浪费,服务器压力,影响业务,往往考虑对同一个ip的连接数,并发数进行限制。下面说说ngx_http_limit_conn_module
模块来实现该需求。该模块可以根据定义的键来限制每个键值的连接数,如同一个IP来源的连接数。并不是所有的连接都会被该模块计数,只有那些正在被处理的
请求(这些请求的头信息已被完全读入)所在的连接才会被计数。
  2. ngx_http_limit_conn_module指令详解
  limit_conn_zone
  语法:limit_conn_zone $variable zone=name:size;
  默认值:none
  配置段:http
  该指令描述会话状态存储区域。键的状态中保存了当前连接数,键的值可以是特定变量的任何非空值(空值将不会被考虑)。$variable定义键,zone=name定义区域名称,后面的limit_conn指令会用到的。size定义各个键共享内存空间大小。
  如:
limit_conn_zone $binary_remote_addr zone=addr:10m;  注释:客户端的IP地址作为键。注意,这里使用的是$binary_remote_addr变量,而不是$remote_addr变量。
  $remote_addr变量的长度为7字节到15字节,而存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。
  $binary_remote_addr变量的长度是固定的4字节,存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。
  1M共享空间可以保存3.2万个32位的状态,1.6万个64位的状态。
  如果共享内存空间被耗尽,服务器将会对后续所有的请求返回 503 (Service Temporarily Unavailable) 错误。
  limit_zone 指令和limit_conn_zone指令同等意思,已经被弃用,就不再做说明了。
  limit_conn_log_level
  语法:limit_conn_log_level info | notice | warn | error
  默认值:error
  配置段:http, server, location
  当达到最大限制连接数后,记录日志的等级。
limit_conn_zone $binary_remote_addr zone=addr:10m;  
    server {
  
    location /www.ttlsa.com/ {
  
      limit_conn addr 1;
  
    }
  
}
  同一IP同一时间只允许有一个连接。
  当多个 limit_conn 指令被配置时,所有的连接数限制都会生效。
  比如,下面配置不仅会限制单一IP来源的连接数,同时也会限制单一虚拟服务器的总连接数:
limit_conn_zone $binary_remote_addr zone=perip:10m;  
limit_conn_zone $server_name zone=perserver:10m;
  
server {
  
    limit_conn perip 10;
  
    limit_conn perserver 100;
  
}
  limit_conn_status
  语法: limit_conn_status code;
  默认值: limit_conn_status 503;
  配置段: http, server, location
  该指定在1.3.15版本引入的。指定当超过限制时,返回的状态码。默认是503。
  limit_rate
  语法:limit_rate rate
  默认值:0
  配置段:http, server, location, if in location
  对每个连接的速率限制。参数rate的单位是字节/秒,设置为0将关闭限速。 按连接限速而不是按IP限制,因此如果某个客户端同时开启了两个连接,那么客户端的整体速率是这条指令设置值的2倍。
  3.完整配置实例
http {  
    limit_conn_zone $binary_remote_addr zone=limit:10m;
  
    limit_conn_log_level info;
  
    server {
  
      location^~ /download/ {
  
            limit_conn limit 4;
  
            limit_rate 200k;
  
            alias /data/www.ttlsa.com/download/;
  
                }
  
    }
  
}
  4.注意事项
  事务都具有两面性的。ngx_http_limit_conn_module
模块虽说可以解决当前面临的并发问题,但是会引入另外一些问题的。如前端如果有做LVS或反代,而我们后端启用了该模块功能,那不是非常多503错误了?
这样的话,可以在前端启用该模块,要么就是设置白名单,也可以与ngx_http_limit_req_module 模块结合起来使用,以达到最好效果。

[*]  Nginx限制请求数ngx_http_limit_req_module模块
  1. 前言
  在《nginx限制连接数ngx_http_limit_conn_module模块》
我们说到了ngx_http_limit_conn_module
模块,来限制连接数。那么请求数的限制该怎么做呢?这就需要通过ngx_http_limit_req_module 模块来实现,该模块可以通过定义的键值来限制请求处理的频率。特别的,可以限制来自单个IP地址的请求处理频率。 限制的方法如同漏斗,每秒固定处理请求数,推迟过多请求。
  2. ngx_http_limit_req_module模块指令
  limit_req_zone
  语法: limit_req_zone $variable zone=name:size rate=rate;
  默认值: none
  配置段: http
  设置一块共享内存限制域用来保存键值的状态参数。 特别是保存了当前超出请求的数量。 键的值就是指定的变量(空值不会被计算)。如
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;  说明:区域名称为one,大小为10m,平均处理的请求频率不能超过每秒一次。
  键值是客户端IP。
  使用$binary_remote_addr变量, 可以将每条状态记录的大小减少到64个字节,这样1M的内存可以保存大约1万6千个64字节的记录。
  如果限制域的存储空间耗尽了,对于后续所有请求,服务器都会返回 503 (Service Temporarily Unavailable)错误。
  速度可以设置为每秒处理请求数和每分钟处理请求数,其值必须是整数,所以如果你需要指定每秒处理少于1个的请求,2秒处理一个请求,可以使用 “30r/m”。
  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级别。
  limit_req_status
  语法: limit_req_status code;
  默认值: limit_req_status 503;
  配置段: http, server, location
  该指令在1.3.15版本引入。设置拒绝请求的响应状态码。
  limit_req
  语法: limit_req zone=name ;
  默认值: —
  配置段: http, server, location
  设置对应的共享内存限制域和允许被处理的最大请求数阈值。
如果请求的频率超过了限制域配置的值,请求处理会被延迟,所以所有的请求都是以定义的频率被处理的。
超过频率限制的请求会被延迟,直到被延迟的请求数超过了定义的阈值,这时,这个请求会被终止,并返回503 (Service Temporarily
Unavailable) 错误。这个阈值的默认值为0。如:
limit_req_zone $binary_remote_addr zone=ttlsa_com:10m rate=1r/s;  
    server {
  
    location /www.ttlsa.com/ {
  
      limit_req zone=ttlsa_com burst=5;
  
    }
  
}
  限制平均每秒不超过一个请求,同时允许超过频率限制的请求数不多于5个。
  如果不希望超过的请求被延迟,可以用nodelay参数,如:
limit_req zone=ttlsa_com burst=5 nodelay;  3.完整配置实例
http {  
    limit_req_zone $binary_remote_addr zone=ttlsa_com:10m rate=1r/s;
  
    server {
  
      location^~ /download/ {
  
            limit_req zone=ttlsa_com burst=5;
  
            alias /data/www.ttlsa.com/download/;
  
      }
  
    }
  
}
  可能要对某些IP不做限制,需要使用到白名单。

[*]  nginx白名单
  1.简介
  在《nginx限制连接数ngx_http_limit_conn_module模块》和《nginx限制请求数ngx_http_limit_req_module模块》中会对所有的IP进行限制。在某些情况下,我们不希望对某些IP进行限制,如自己的反代服务器IP,公司IP等等。这就需要白名单,将特定的IP加入到白名单中。下面来看看nginx白名单实现方法,需要结合geo和map指令来实现。geo和map指令使用方法参见下面文章。《nginx geo使用方法》和《nginx map使用方法》。不扯蛋了,看配置。
http {  
      geo $whiteiplist{
  
      default 1;
  
      127.0.0.1 0;
  
      10.0.0.0/8 0;
  
      121.207.242.0/24 0;
  
    }
  
    map $whiteiplist$limit {
  
      1 $binary_remote_addr;
  
      0 "";
  
    }
  
    limit_conn_zone $limit zone=limit:10m;
  
    server {
  
      listen       8080;
  
      server_nametest.ttlsa.com;
  
      location ^~ /ttlsa.com/ {
  
                limit_conn limit 4;
  
                limit_rate 200k;
  
                alias /data/www.ttlsa.com/data/download/;
  
      }
  
    }
  
}
  技术要点:
  1. geo指令定义一个白名单$whiteiplist, 默认值为1, 所有都受限制。 如果客户端IP与白名单列出的IP相匹配,则$whiteiplist值为0也就是不受限制。
  2. map指令是将$whiteiplist值为1的,也就是受限制的IP,映射为客户端IP。将$whiteiplist值为0的,也就是白名单IP,映射为空的字符串。
  3. limit_conn_zone和limit_req_zone指令对于键为空值的将会被忽略,从而实现对于列出来的IP不做限制。
  测试方法:
# ab -c 100 -n 300 http://test.ttlsa.com:8080/ttlsa.com/docs/pdf/nginx_guide.pdf  2.nginx geo使用方法
  geo指令使用ngx_http_geo_module模块提供的。默认情况下,nginx有加载这个模块,除非人为的 –without-http_geo_module。
  ngx_http_geo_module模块可以用来创建变量,其值依赖于客户端IP地址。
  geo指令
  语法: geo [$address] $variable { … }
  默认值: —
  配置段: http
  定义从指定的变量获取客户端的IP地址。默认情况下,nginx从$remote_addr变量取得客户端IP地址,但也可以从其他变量获得。如
geo $remote_addr $geo {  
      default 0;
  
      127.0.0.1 1;
  
}
  
geo $arg_ttlsa_com $geo {
  
      default 0;
  
      127.0.0.1 1;
  
}
  如果该变量的值不能代表一个合法的IP地址,那么nginx将使用地址“255.255.255.255”。
  nginx通过CIDR或者地址段来描述地址,支持下面几个参数:
  delete:删除指定的网络
  default:如果客户端地址不能匹配任意一个定义的地址,nginx将使用此值。 如果使用CIDR,可以用“0.0.0.0/0”代替default。
  include: 包含一个定义地址和值的文件,可以包含多个。
  proxy:定义可信地址。 如果请求来自可信地址,nginx将使用其“X-Forwarded-For”头来获得地址。 相对于普通地址,可信地址是顺序检测的。
  proxy_recursive:开启递归查找地址。
如果关闭递归查找,在客户端地址与某个可信地址匹配时,nginx将使用“X-Forwarded-For”中的最后一个地址来代替原始客户端地址。如果
开启递归查找,在客户端地址与某个可信地址匹配时,nginx将使用“X-Forwarded-For”中最后一个与所有可信地址都不匹配的地址来代替原
始客户端地址。
  ranges:使用以地址段的形式定义地址,这个参数必须放在首位。为了加速装载地址库,地址应按升序定义。
geo $country {  
    default      ZZ;
  
    include      conf/geo.conf;
  
    delete         127.0.0.0/16;
  
    proxy          192.168.100.0/24;
  
    proxy          2001:0db8::/32;
  
    127.0.0.0/24   US;
  
    127.0.0.1/32   RU;
  
    10.1.0.0/16    RU;
  
    192.168.1.0/24 UK;
  
}
  
vim conf/geo.conf
  
10.2.0.0/16    RU;
  
192.168.2.0/24 RU;
  地址段例子:
geo $country {  
    ranges;
  
    default                   ZZ;
  
    127.0.0.0-127.0.0.0       US;
  
    127.0.0.1-127.0.0.1       RU;
  
    127.0.0.1-127.0.0.255   US;
  
    10.1.0.0-10.1.255.255   RU;
  
    192.168.1.0-192.168.1.255 UK;
  
}
  使用实例
  上面的例子几乎都是官网说明例子。下面举例说明便于理解该指令的用法。
  1. 使用默认变量也就是$remote_addr
http {  
    #geo $remote_addr $ttlsa_com {
  
    geo $ttlsa_com {
  
      default 0;
  
      127.0.0.1 1;
  
    }
  
    server {
  
      listen       8080;
  
      server_nametest.ttlsa.com;
  
      location /hello {
  
            default_type text/plain;
  
            echo $ttlsa_com;
  
            echo $arg_boy;
  
      }
  
    }
  
}
  
# curl 127.0.0.1:8080/hello?boy=默北
  
1
  
默北
  2. 使用指定变量
http {  
      geo $arg_boy $ttlsa_com {
  
      default 0;
  
      127.0.0.1 1;
  
      8.8.8.8 2;
  
      }
  
    server {
  
      listen       8080;
  
      server_nametest.ttlsa.com;
  
      location /hello {
  
            default_type text/plain;
  
            echo $ttlsa_com;
  
            echo $arg_boy;
  
      }
  
    }
  
}
  
# curl 127.0.0.1:8080/hello?boy=8.8.8.8
  
2
  
8.8.8.8
  3. 匹配原则
http {  
      geo $arg_boy $ttlsa_com {
  
      default 0;
  
      127.0.0.1/24 24;
  
      127.0.0.1/32 32;
  
      8.8.8.8 2;
  
}
  
    server {
  
      listen       8080;
  
      server_nametest.ttlsa.com;
  
      location /hello {
  
            default_type text/plain;
  
            echo $ttlsa_com;
  
            echo $arg_boy;
  
      }
  
    }
  
}
  
# curl 127.0.0.1:8080/hello?boy=127.0.0.1
  
32
  
127.0.0.1
  
# curl 127.0.0.1:8080/hello?boy=127.0.0.12
  
24
  
127.0.0.12
  warning:geo指令主要是根据IP来对变量进行赋值的。因此geo块下只能定义IP或网络段,否则会报错“nginx: invalid network”。
  3.nginx map使用方法
  map指令使用ngx_http_map_module模块提供的。默认情况下,nginx有加载这个模块,除非人为的 –without-http_map_module。
  ngx_http_map_module模块可以创建变量,这些变量的值与另外的变量值相关联。允许分类或者同时映射多个值到多个不同值并储存到一个变量
中,map指令用来创建变量,但是仅在变量被接受的时候执行视图映射操作,对于处理没有引用变量的请求时,这个模块并没有性能上的缺失。
  ngx_http_map_module模块指令说明
  map
  语法: map $var1 $var2 { … }
  默认值: —
  配置段: http
  map为一个变量设置的映射表。映射表由两列组成,匹配模式和对应的值。
  在 map 块里的参数指定了源变量值和结果值的对应关系。
  匹配模式可以是一个简单的字符串或者正则表达式,使用正则表达式要用(‘~’)。
  一个正则表达式如果以 “~” 开头,表示这个正则表达式对大小写敏感。以 “~*”开头,表示这个正则表达式对大小写不敏感。
map $http_user_agent $agent {  
      default "";
  
      ~curl curl;
  
      ~*apachebench" ab;
  
}
  正则表达式里可以包含命名捕获和位置捕获,这些变量可以跟结果变量一起被其它指令使用。
map $uri $value {  
    /ttlsa_com                   /index.php;
  
    ~^/ttlsa_com/(?.*)$/boy/;
  
    ~/fz(/.*)                  /index.php?;
  
}
  不能在map块里面引用命名捕获或位置捕获变量。如~^/ttlsa_com/(.*)/boy/$1; 这样会报错nginx: unknownvariable。如果源变量值包含特殊字符如‘~’,则要以‘\’来转义。
map $http_referer $value {  
    Mozilla    111;
  
    \~Mozilla222;
  
}
  结果变量可以是一个字符串也可以是另外一个变量。
map $num $limit {  
          1 $binary_remote_addr;
  
          0 "";
  
}
  map指令有三个参数:
  default : 指定如果没有匹配结果将使用的默认值。当没有设置 default,将会用一个空的字符串作为默认的结果。
  hostnames : 允许用前缀或者后缀掩码指定域名作为源变量值。这个参数必须写在值映射列表的最前面。
  include : 包含一个或多个含有映射值的文件。
  如果匹配到多个特定的变量,如掩码和正则同时匹配,那么会按照下面的顺序进行选择:
  1. 没有掩码的字符串
  2. 最长的带前缀的字符串,例如: “*.example.com”
  3. 最长的带后缀的字符串,例如:“mail.*”
  4. 按顺序第一个先匹配的正则表达式 (在配置文件中体现的顺序)
  5. 默认值
  map_hash_bucket_size

  语法: map_hash_bucket_size>  默认值: map_hash_bucket_size 32|64|128;
  配置段: http
  指定一个映射表中的变量在哈希表中的最大值,这个值取决于处理器的缓存。
  map_hash_max_size

  语法: map_hash_max_size>  默认值: map_hash_max_size 2048;
  配置段: http
  设置映射表对应的哈希表的最大值。
  实例:
http {  
      map $http_user_agent $agent {
  
      ~curl curl;
  
      ~*chrome chrome;
  
    }
  
    server {
  
      listen       8080;
  
      server_nametest.ttlsa.com;
  
      location /hello {
  
            default_type text/plain;
  
            echo http_user_agent: $http_user_agent;
  
            echo agent: agent:$agent;
  
      }
  
    }
  
}
  
# curl 127.0.0.1:8080/hello
  
http_user_agent: curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
  
agent: curl
  本文转自:http://www.ttlsa.com/nginx/using-nginx-map-method/


页: [1]
查看完整版本: Nginx学习(四)Nginx限制整合