Nginx的请求限制

在配置nginx的过程中我们需要考虑受到攻击或恶意请求的情况,比如单用户恶意发起大量请求,这时Nginx的请求限制可以帮助我们对其进行限制。

连接频率限制 : limit_conn_module

请求频率限制 : limit_req_module

理解:连接频率限制和请求频率限制都可以实现Nginx的请求限制 , 但是他们的实现原理是不一样的 , 区别就在于连接和请求上 , http协议的链接与请求 , http协议是建立在tcp协议之上的,要完成一次http的请求,先要进行tcp的3次握手建立http的连接 , 然后才进行http的request和response(请求和响应) , 现在http1.1以上的版本已经可以实现一次建立http的连接进行多次的http的request和response(请求和响应) ,最后客户端和服务端不断的来发送FIN包和ACK包来保持HTTP的连接 。

如果面对抢购和秒杀需求来限制 , 个人觉得连接频率限制和请求频率限制应该配合使用 , 使用连接频率限制同一IP同时只能有3个连接, 再使用请求频率限制对于同一ip的请求,限制平均速率为5个请求/秒 , 这样是不是比单独只使用一种限制要好很多?

比如只使用连接频率限制 , 由于一次建立http的连接可以进行多次的请求和响应 , 我们无法精确的限制同一ip同时发起多少次的http请求 ;

比如只使用请求频率限制 , 可以精确的限制同一ip1秒只能发起5次的http请求 , 假如同一ip1秒内发起了100000次请求 , 虽然限制了只有5次成功响应 , 但是其他的99995次的请求TCP握手建立http连接是不是会消耗服务器资源?

所以,个人觉得连接频率限制和请求频率限制应该配合使用!


HTTP协议的连接与请求

HTTP请求建立在一次TCP连接基础上

一次TCP连接至少产生一次HTTP请求


连接限制

ngx_http_limit_conn_module模块用于限制每个定义键的连接数,特别是来自单个IP地址的连接数。

配置示例

http {

...

#对单个ip、单个会话同时存在的连接数的限制。这里定义一个存储区conn_zone,conn_zone的容量是1m,该存储区针对于变量$binary_remote_add生效,这里是针对单个IP生效。该模块只是一个定义,配置在http配置段,需要配合limit_conn指令使用才生效, limit_conn one 1表示该location段使用conn_zone定义的 limit_conn_zone ,对单个IP限制同时存在一个连接。

limit_conn_zone $binary_remote_addr zone=conn_zone:1m;

server {

​ location / {

​ limit_conn conn_zone 1;

​ }

}

做个演示:

未开启连接限制时做个压力测试

1、安装ab测试命令

yum install httpd-tools -y

2、ab 参数
-n : 总共需要访问多少次
-c : 每次访问多少个

ab -n 10000 -c 1000 http://192.168.58.100/index.html

Complete requests: 10000

Failed requests: 78

这里模拟了10万个请求 , 1000个并发 , 78个请求失败,打开nginx的错误日志查看都是打开文件失败的错误 ( open() "/usr/share/nginx/html/50x.html" failed (24: Too many open files))! 想象一下 , 如果我们是一个商城程序的API接口 , 正常情况下 , 同一个IP下10万个请求1000个并发 , 算不算恶意攻击?那么就需要做一下连接限制了噻 , 具体怎么限制根绝具体的逻辑去处理 , 我们这里简单的限制一下(启用配置示例的连接限制)再次做个压力测试:

ab -n 10000 -c 1000 http://192.168.58.100/index.html

Complete requests: 100000

Failed requests: 43616

开启连接限制对单个IP限制同时只能存在一个连接,这里模拟了10万个请求 , 1000个并发 , 43616个请求失败,打开nginx的错误日志查看下错误全是连接限制的作用(limiting connections by zone "conn_zone") , 我们知道"现在http1.1以上的版本已经可以实现一次建立http的连接进行多次的http的request和response(请求和响应) " , 大家想想 , 如果我们需要做一个抢购和秒杀 , 是不是需要对单个抢购和秒杀限制连接单个IP同时只能存在一个或者多个连接的限制?不然人家写个脚本程序运行在十台八台的机器上疯狂的请求怎么办?当然这只是一个比较简单的应用场景 , 更多的还是需要自己思考与摸索.


请求限制

ngx_http_limit_req_module模块用于限制请求的处理速率,特别是单一的IP地址的请求的处理速率。使用“漏桶”方法进行限制。

配置示例

http {

...

#$binary_remote_addr表示的是客户端的地址,zone=req_zone:1m代表的是开辟了一个名为req_zone的1M的空间,1M的空间可以存储多少个$binary_remote_addr这里不解释了 , Nginx官网文档介绍的相当清除 , 速率rate=1r/s代表的是每秒1个 , 所以这里定义的配置代表:对于同一ip的请求,限制平均速率为1个请求/秒。

limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s;

server {

​ ...

​ location / {

​ root /usr/share/nginx/html;

​ index index.html index.htm;

​ #请求限制 : 对于符合名为req_zone的limit_req_zone 配置(对于同一ip的请求,限制平均速率为1个请求/秒) , 超过部分进行延迟处理,若超过3个请求/秒,丢弃超过部分。

​ #limit_req zone=req_zone burst=3 nodelay;

​ #请求限制 : 对于符合名为req_zone的limit_req_zone 配置 ,超过部分进行延迟处理,若超过3个请求/秒,所有请求都被过度延迟,直到名为req_zone的limit_req_zone 配置设置的1M存储区被占满,如果存储区耗尽,则删除最近最少使用的状态。即使在此之后无法创建新状态,请求也会因错误而终止。

​ #limit_req zone=req_zone burst=3;

​ #请求限制 : 对于符合名为req_zone的limit_req_zone 配置(对于同一ip的请求,限制平均速率为1个请求/秒) 若超过1个请求/秒,所有请求都被过度延迟,直到名为req_zone的limit_req_zone 配置设置的1M存储区被占满,如果存储区耗尽,则删除最近最少使用的状态。即使在此之后无法创建新状态,请求也会因错误而终止。

​ #limit_req zone=req_zone;

​ }

基本指令

limit_req_zone

语法:limit_req_zone key zone=name:size rate=rate;

只能在http块中使用

此指令用于声明请求限制zonezone可以保存各种key的状态,namezone的唯一标识,size代表zone的内存大小,rate指定速率限制。

参数详解:

1.key

若客户的请求匹配了key,则进入zone。可以是文本、变量,通常为Nginx变量。

$binary_remote_addr(客户的ip),$uri(不带参数的请求地址)$request_uri(带参数的请求地址)$server_name(服务器名称)

支持组合使用,使用空格隔开。

2.zone

使用zone=test,指定此zone的名字为test。

3.size

在zone=name后面紧跟:size,指定此zone的内存大小。如zone=name:10m,代表name的共享内存大小为10m。通常情况下,1m可以保存16000个状态。

4.rate

使用rate=1r/s,限制平均1秒不超过1个请求。使用rate=1r/m,限制平均1分钟不超过1个请求。

例子:

limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;

limit_req_zone $binary_remote_addr $uri zone=two:10m rate=1r/s;

同一ip不同请求地址,进入名为one的zone,限制速率为5请求/秒

同一ip同一请求地址,进入名为two的zone,限制速率为1请求/秒

limit_req zone

语法:limit_req zone=name [burst=number] [nodelay];

可在http, server, location块中使用

此指令用于设置共享的内存zone和最大的突发请求大小。

若请求速率超过了limit_req_zone中指定的rate但小于limit_req中的burst,则进行延迟处理,若再超过burst,就可以通过设置nodelay对其进行丢弃处理。

参数详解:

1.zone

使用zone=name指定使用名为namezone,这个zone之前使用limit_req_zone声明过。

2.burst(可选)

burst用于指定最大突发请求数。许多场景下,单一地限制rate并不能满足需求,设置burst,可以延迟处理超过rate限制的请求。

3.nodelay(可选)

如果设置了nodelay,在突发请求数大于burst时,会丢弃掉这部分请求。因为如果只是延迟处理,就像”漏斗“,一旦上面加得快(请求),下面漏的慢(处理速度),”漏斗“总会有溢出的时候。这时,丢弃掉溢出的部分就显得很有意义了。

单客户分为三种情况:

请求速率 < rate(1r/s),正常处理

rate(1r/s) < 请求速率 < burst(5r/s),大于rate部分延迟

burst(5r/s) < 请求速率,大于burst部分丢弃(返回503服务暂时不可用)


做个演示:

未开启请求限制时做个压力测试

ab -n 100000 -c 1000 http://192.168.58.100/index.html

Complete requests: 10000

Failed requests: 0

这里模拟了10万个请求 , 1000个并发 , 全部请求成功! 想想一下 , 如果我们是一个商城程序的API接口 , 正常情况下,同一个IP下10万个请求算不算恶意攻击?那么就需要做一下请求限制了噻 , 具体怎么限制根绝具体的逻辑去处理 , 我们这里简单的限制一下:

同一ip请求,进入名为req_zone的zone,限制速率为20次请求/秒,

超过部分进行延迟处理,若超过10个请求/秒,丢弃超过部分。

http {

limit_req_zone $binary_remote_addr zone=req_zone:1m rate=20r/s;

server {

​ ...

​ location / {

​ ...

​ #limit_req zone=req_zone burst=10 nodelay;

​ }

修改了配置之后平滑重启一下nginx -s reload , 再次使用之前的参数做个压力测试看看

同一IP发起了请求10万次, nginx只接受处理了100次,是不是nginx的压力一下子就小了

Complete requests: 100000

Failed requests: 99900

Nginx请求连接限制的更多相关文章

  1. nginx长连接设置

    http { keepalive_timeout 20; --长连接timeout keepalive_requests 8192; --每个连接最大请求数} events { worker_conn ...

  2. nginx 请求限制

    1.nginx 请求限制 1.连接频率限制 - limit_conn_module 2.请求频率限制 - limit_req_module 连接限制的语法 请求限制的语法 limit_conn_zon ...

  3. Nginx请求限制配置

    Nginx请求限制配置 请求限制可以通过两种方式来配置,分别是  连接频率限制和请求频率限制 首先我们要知道什么是http请求和连接,浏览器和服务端首先通过三次握手完成连接,然后发起请求,传输请求参数 ...

  4. 从压测碰到的诡异断连问题聊聊Nginx的连接管理

    本文主要分享一个在压测Nginx反向代理服务过程中碰到的连接异常断开问题,包括问题的定位与复现,最后由这个实际问题引申聊一下Nginx的连接管理. 本博客已迁移至CatBro's Blog,那是我自己 ...

  5. WiFi-ESP8266入门http(3-4)网页一键配网(1若为普通wifi直连 2若为西电网页认证自动网页post请求连接)+网页按钮灯控+MQTT通信

    网页一键配网(1若为普通wifi直连  2若为西电网页认证自动网页post请求连接)+网页按钮灯控+MQTT通信 工程连接:https://github.com/Dongvdong/ESP8266_H ...

  6. 客户端向服务端请求连接是出现"ssh : Connection refused"原因有哪些

    注意:服务端的sshd服务已经正常开启 (可以正常进行连接) 1.在服务端负载比较高的情况下客户端请求连接时会出现连接被拒绝的情况

  7. Nginx 多进程连接请求/事件分发流程分析

    Nginx使用多进程的方法进行任务处理,每个worker进程只有一个线程,单线程循环处理全部监听的事件.本文重点分析一下多进程间的负载均衡问题以及Nginx多进程事件处理流程,方便大家自己写程序的时候 ...

  8. Nginx限制连接和请求

    一.ngx_http_limit_conn_module对同一个ip/server的连接数做限制.配置指令:limit_conn_zone语法: limit_conn_zone $variable z ...

  9. nginx 请求负载 转发规则设置

    (1)轮询(默认) weight=5;         #本机上的Squid开启3128端口,不是必须要squid         server 192.168.8.2x:80    weight=1 ...

随机推荐

  1. fmt的API介绍(版本: 7.0.1)

    !!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!! 作者:mohist 本文翻译: https://fmt.dev/latest/api.html 水平有限,仅供参 ...

  2. 【LeetCode】405. Convert a Number to Hexadecimal 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 Java解法 Python解法 日期 题目地址:ht ...

  3. 3998 - Prime k-tuple

    {p1,..., pk : p1 < p2 <...< pk} is called a prime k -tuple of distance s if p1, p2,..., pk ...

  4. [C++]高效C/C ++编程tips

    Effective C++ 视C++ 为一个语言联邦(C.Object-Oriented C++.Template C++.STL) 宁可以编译器替换预处理器(尽量以const.enum.inline ...

  5. [opencv]计算多边形逼近曲线的长度

    //利用曲线逼近,计算逼近曲线的长度 //首先创建一个逼近曲线 vector<Point2f> approx; approxPolyDP(contours[i], approx, 2, t ...

  6. 【odoo】关于odoo二开模块规范的一点思考

    老韩头的开发日常 ☞ [好书学习]系列 背景 作为丙方,完成了甲方的二开需求.因此,在设计二开模块的时候,考虑的是当时所列的需求清单,并整合到一个二开模块中.完成交付后,客户评价蛮好的.因此,成功的为 ...

  7. 编写Java程序,定义士兵类(Soldiers)并初始化5个士兵对象。

    返回本章节 返回作业目录 需求说明: 创建士兵类(Soldiers),定义有一个String类型参数name,代表士兵的姓名,两个int类型变量x和y,分别表示士兵所在的坐标位置,x代表横坐标,y代表 ...

  8. .net core中的Options重新加载机制

    Options是.net core提出的一种辅助配置机制,即选项. 目前,我们可以使用的Options有五种(源码): IOptionsFactory<>:Options的创建工厂(Sin ...

  9. ElasticSearch启动失败:master not discovered or elected yet, an election requires at least X nodes with ids from [XXXXX]

    这个问题困扰过我一段时间,它其实是说未能选举出一个主节点,最后在官网教程中找到答案. 首先是启动(链接): 总结下来就是,如果ES集群是第一次启动,那么需要 cluster.initial_maste ...

  10. Hadoop开启Kerberos安全模式

    Hadoop开启Kerberos安全模式, 基于已经安装好的Hadoop的2.7.1环境, 在此基础上开启Kerberos安全模式. 1.安装规划 已经安装好Hadoop的环境 10.43.159.7 ...