Nginx 的 ngx_http_limit_conn_module、ngx_http_limit_req_module中的limit相关配置参数

本文深入解析Nginx的ngx_http_limit_req_module和ngx_http_limit_conn_module模块,阐述漏斗算法和令牌桶算法在流量控制中的应用,包括limit_req_zone、limit_req、limit_req_log_level、limit_conn_zone和limit_conn的配置与工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ngx_http_limit_req_module 模块(nginx 自带本模块除非编译时使用了–without-http_limit_req_module)

本模块基于漏斗算法(Leaky Bucket)
该算法有两种处理方式(水桶满水之后)

  • Traffic Shaping:暂时拦截住上方水的向下流动,等待桶中的一部分水漏走后,再放行上方水。此方式的核心是等待。
  • Traffic Policing:溢出的上方水直接抛弃。此方式的核心是抛弃。

这两种是常见的流速的控制方法。

名称默认配置作用域解读模块
limit_req_zone没有默认值,语法 limit_req_zone key zone=name:size rate=rate;http第一个参数指定key,第二个参数指定zone名称和元数据的内存大小,第三个参数rate指定单位时间的请求数阈值ngx_http_limit_req_module
limit_req没有默认值,语法 limit_req zone=name [burst=number] [nodelay];http, server, location指定zone的burst大小ngx_http_limit_req_module
limit_req_log_levellimit_req_log_level error;http, server, location指定触发req limit时打印的日志级别ngx_http_limit_req_module
实例配置

nginx 配置文件增加配置,为方便测试我将limit_req_zone、limit_req放在http段,使其全局生效。
如果针对各个虚拟主机单独配置,需要注意不能用include将各个虚拟主机(include vhost/*.conf)的方式,经测试此模块不支持这样部署方式(测试版本nginx1.8 其他版本没有测试),需将各个虚拟主机配置在nginx.conf里

http {
...
	limit_req_zone $binary_remote_addr zone=one:10m  rate=1r/s;
	limit_req zone=one burst=5 nodelay;
...

参数说明:
第一段:

  • *$binary_remote_addr :表示通过remote_addr这个标识来做限制,“binary_”的目的是缩写内存占用量,是限制同一客户端ip地址
  • zone=one:10m:表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息*
  • rate=1r/s:表示允许相同标识的客户端的访问频次,这里限制的是每秒1次,即每秒只处理一个请求,还可以有比如30r/m的,即限制每2秒访问一次,即每2秒才处理一个请求。
    第二段:
  • zone=one :设置使用哪个配置区域来做限制,与上面limit_req_zone 里的name对应
  • burst=5:重点说明一下这个配置,burst爆发的意思,这个配置的意思是设置一个大小为5的缓冲区当有大量请求(爆发)过来时,超过了访问频次限制的请求可以先放到这个缓冲区内等待,但是这个等待区里的位置只有5个,超过的请求会直接报503的错误然后返回。
  • nodelay:
    • 如果设置,会在瞬时提供处理(burst + rate)个请求的能力,请求超过(burst + rate)的时候就会直接返回503,永远不存在请求需要等待的情况。(这里的rate的单位是:r/s)
    • 如果没有设置,则所有请求会依次等待排队
      burst参数主要采用了令牌桶算法。令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据数目,并允许突发数据的发送。
      令牌桶这种控制机制基于令牌桶中是否存在令牌来指示什么时候可以发送流量。令牌桶中的每一个令牌都代表一个字节。如果令牌桶中存在令牌,则允许发送流量;如果令牌桶中不存在令牌,则不允许发送流量。因此,如果突发门限被合理地配置并且令牌桶中有足够的令牌,那么流量就可以以峰值速率发送。

令牌桶算法的基本过程如下:

  • 假如用户配置的平均发送速率为10r/s,则每隔0.1秒一个令牌被加入到桶中;
  • 假设桶最多可以存发b个令牌。如果令牌到达时令牌桶已经满了,那么这个令牌会被丢弃;
  • 当一个n个字节的数据包到达时,就从令牌桶中删除n个令牌,并且数据包被发送到网络;
  • 如果令牌桶中少于n个令牌,那么不会删除令牌,并且认为这个数据包在流量限制之外;
  • 算法允许最长b个字节的突发,但从长期运行结果看,数据包的速率被限制成常量r。对于在流量限制外的数据包可以以不同的方式处理:
    - 它们可以被丢弃;
    - 它们可以排放在队列中以便当令牌桶中累积了足够多的令牌时再传输;
    - 它们可以继续发送,但需要做特殊标记,网络过载的时候将这些特殊标记的包丢弃。

注意:令牌桶算法不能与另外一种常见算法“漏斗算法(Leaky Bucket)”相混淆。这两种算法的主要区别在于“漏斗算法”能够强行限制数据的传输速率,而“令牌桶算法”在能够限制数据的平均传输数据外,还允许某种程度的突发传输。在“令牌桶算法”中,只要令牌桶中存在令牌,那么就允许突发地传输数据直到达到用户配置的门限,因此它适合于具有突发特性的流量。

关于添加或不添加burst、nodelay的区别:
请参考:https://blog.youkuaiyun.com/hellow__world/article/details/78658041

ngx_http_limit_conn_module (nginx 自带本模块除非编译时使用了–without-http_limit_conn_module)

ngx_http_limit_conn_module 对于一些服务器流量异常、负载过大,甚至是大流量的恶意攻击访问等,进行并发数的限制;该模块可以根据定义的键来限制每个键值的连接数,只有那些正在被处理的请求(这些请求的头信息已被完全读入)所在的连接才会被计数。该模块提供了两个配置参数,limit_conn_zone 和 limit_conn ,其中 limit_conn_zone 只能配置在 http{} 段,而 limit_conn 则可以配置于http{},server{},location{} 区段中。

limit_conn_zone
语法:limit_conn_zone $variable zone=name:size;
配置段:http

该指令描述会话状态存储区域。键的状态中保存了当前连接数,键的值可以是特定变量的任何非空值(空值不会被考虑)。$variable 定义键,zone=name 定义区域名称,主要作用与后面的 limit_conn。size 定义各个键共享内存空间大小

    limit_conn_zone $binary_remote_addr zone=one: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_conn

语法:limit_conn zone_name number
配置段:http,server,location

该指令指定每个给定键值的最大同时连接数,当超过这个数字时返回503(Service )错误。如(同一IP同一时间只允许有20个连接)
    limit_conn  one  20;
使用注意事项

事务都具有两面性的。ngx_http_limit_conn_module 模块虽说可以解决当前面临的并发问题,但是会引入另外一些问题的。如前端如果有做LVS或反代,而我们后端启用了该模块功能,那不是非常多503错误了?这样的话,可以在前端启用该模块,要么就是设置白名单。

<think>我们有一个关于Nginx配置的问题:用户希望在upstream模块中配置max_conns(限制最大连接数)并实现请求排队等待。根据提供的引用信息,我们可以知道:1.max_conns参数可以设置在upstream的server中,用于限制每台服务器的最大连接数,起到保护服务器避免过载的作用(引用[1]和[3])。2.但是,默认情况下,如果超过max_conns,Nginx会直接返回502错误(BadGateway)。用户希望实现的是排队等待,而不是直接返回错误。因此,我们需要一种机制来让超过连接数的请求排队等待,而不是立即拒绝。解决方案:在Nginx的商业版本(NginxPlus)中,提供了queue指令来实现请求排队。但是,在开源版本的Nginx中,并没有这个指令。然而,我们可以通过其他方法模拟排队等待的效果,例如:1.使用Nginxlimit_req模块进行速率限制,但这不是针对每个后端服务器的连接数,而是针对客户端的请求速率。2.使用第三方模块,例如:nginx-upstream-fair(但需要重新编译Nginx,且可能不稳定)。3.使用Nginx的error_page指令,当遇到502错误时重试(但这不是真正的排队,而是重试)。但是,用户的需求是在达到max_conns时排队等待,而不是重试或限速。考虑到开源Nginx本身不支持排队,我们可以采用以下替代方案:方案1(推荐使用NginxPlus):如果可以使用NginxPlus,则可以在upstream块中使用queue指令,例如:```upstreambackend{serverbackend1.example.commax_conns=10;serverbackend2.example.commax_conns=10;queue100timeout=60;}```这里,queue指令设置了一个队列,当超过max_conns的请求可以在这个队列中等待(最多100个请求),等待超时时间为60秒。方案2(使用开源Nginx的替代方法):在开源版本中,我们可以使用lua脚本来实现类似的功能,但这需要安装OpenResty(集成了Lua的Nginx)或者自己编译Nginx并添加lua模块。示例配置(使用OpenResty):```http{lua_package_path"/path/to/lua/scripts/?.lua;;";upstreambackend{serverbackend1.example.commax_conns=10;serverbackend2.example.commax_conns=10;}server{listen80;location/{access_by_lua_block{--这里可以编写Lua脚本来控制请求排队--但请注意,这需要自己实现一个队列机制,可能比较复杂}proxy_passhttp://backend;}}}```但这种方法实现起来较为复杂,需要自己管理队列,并且要考虑并发控制。方案3(使用第三方模块):可以尝试使用第三方模块,如:https://github.com/nginx-clojure/nginx-clojure(使用其他语言编写扩展)或者https://github.com/cfsego/nginx-upstream-queue(一个专门实现排队的模块,但可能不成熟)。方案4(使用负载均衡算法和重试):虽然不能直接排队,但我们可以通过设置max_fails和fail_timeout来让Nginx在服务器过载时(返回502)将其标记为失败,并重试其他服务器。但是,如果所有服务器都过载,则仍然会返回502。然后,我们可以使用error_page捕获502,并重试(使用proxy_next_upstream和重试次数)。但这不是排队,而是重试。配置示例(部分):```upstreambackend{serverbackend1.example.commax_conns=10;serverbackend2.example.commax_conns=10;}server{listen80;location/{proxy_passhttp://backend;proxy_next_upstreamerrortimeouthttp_502;#当遇到502时,尝试下一个服务器proxy_next_upstream_tries3;#最多尝试3次,包括第一次proxy_next_upstream_timeout30s;#整个重试的超时时间error_page502=@retry;#如果最终还是502,则进入@retrylocation}location@retry{#这里可以设置等待一段时间后重试,例如使用proxy_cache_lock或者lua脚本等待后重试#但注意:简单的重试可能造成请求风暴,需要谨慎#或者可以返回一个等待页面,让客户端稍后重试}}```然而,用户要求的是在服务端排队,而不是让客户端重试。总结:-如果可以使用NginxPlus,则直接使用queue指令。-如果使用开源版本,并且愿意使用OpenResty,则可以通过Lua脚本实现一个队列(例如使用共享内存和定时器),但开发复杂。-或者,考虑使用其他负载均衡器,如HAProxy(它有一个“maxqueue”参数)或Apachehttpd,它们可能支持排队。因此,根据用户的需求,最直接的方法是使用NginxPlus的queue指令。配置示例(NginxPlus):```http{upstreamapi_server{serverlocalhost:18080max_conns=10;serverlocalhost:63344max_conns=10;queue100timeout=60;#最多允许100个请求排队,超时时间为60秒}server{location/{proxy_passhttp://api_server;#其他代理设置...}}}```对于开源Nginx,目前没有内置的解决方案。如果必须使用开源版本,可能需要考虑其他替代方案。相关问题:1.NginxPlus中的queue指令有哪些参数?2.如何在开源Nginx中通过Lua实现请求排队?3.除了Nginx,还有哪些负载均衡器支持请求排队?4.如何配置Nginx的max_conns参数以保护后端服务器?5.Nginx的max_conns和queue指令如何一起工作?由于用户的问题明确要求使用Nginx,且提到了upstream和max_conns,我们假设用户使用的是开源Nginx。因此,我们需要告知用户开源Nginx不支持排队,但可以给出替代方案。但是,根据引用[1]和[3]中提到的max_conns配置,我们可以先给出max_conns的配置方法,然后解释排队需要额外的手段。因此,回答将分为两部分:1.如何配置max_conns。2.如何实现请求排队等待(说明开源版本的限制和替代方案)。注意:引用[1]中有一个配置示例,其中包含了max_conns,但并没有提到排队。引用[2]介绍了upstream模块和proxy_pass的基本用法。引用[3]和[4]也提到了max_conns和其他参数。所以,我们先给出max_conns的配置,然后讨论排队。配置max_conns:在upstream块中,为每个server配置max_conns参数,例如:```upstreamapi_server{serverlocalhost:18080max_conns=10;serverlocalhost:63344max_conns=15;}```然后,在location中使用proxy_pass指向这个upstream:```location/{proxy_passhttp://api_server;#其他代理设置...}```但是,当某个服务器的连接数达到max_conns时,新的请求将会被Nginx直接拒绝,并返回502错误(如果该服务器是唯一可用的,或者所有服务器都达到max_conns)。为了实现排队,我们需要额外的措施。在开源Nginx中,我们可以使用以下方法模拟排队效果(不完美):1.使用proxy_next_upstream和重试:当返回502时,让请求重试(可能重试到同一个服务器,但可以设置重试次数和超时)。但是,如果后端服务器连接数释放很快,重试可能会成功。但这不是真正的排队,而是重试。2.使用lua脚本:在access阶段,通过lua脚本检查后端服务器的当前连接数(需要自己维护状态),如果超过则延迟处理(使用ngx.sleep)然后重试。但是,这需要共享内存来记录连接数,并且需要与upstream模块协同工作,实现复杂。另一种思路:使用Nginxlimit_conn模块限制整个Nginx实例对某个后端的连接数,然后对超过的请求进行等待(通过limit_conn的延迟效果?),但limit_conn模块是针对客户端IP的,而不是针对后端服务器的。考虑到复杂度,如果用户必须使用排队功能,建议考虑使用NginxPlus或者换用其他负载均衡软件(如HAProxy)。在HAProxy中,可以设置“maxconn”和“maxqueue”参数,例如:```backendmy_backendserverserver1192.168.1.1:80maxconn10maxqueue100```因此,我们给出两种解决方案:1.升级到NginxPlus,使用queue指令。2.使用HAProxy替代Nginx配置maxconn和maxqueue。最后,如果用户坚持使用开源Nginx,我们可以提供一个使用error_page和重试的折中方案(但这不是排队,而是重试):```upstreamapi_server{serverlocalhost:18080max_conns=10;serverlocalhost:63344max_conns=10;}server{location/{proxy_passhttp://api_server;proxy_next_upstreamerrortimeouthttp_502;proxy_next_upstream_tries10;#设置较大的重试次数proxy_next_upstream_timeout60s;#超时时间#如果所有服务器都返回502,则最终返回502error_page502=@handle_502;}location@handle_502{#这里可以返回一个自定义错误页面,或者使用lua脚本进行等待和重试#例如,返回一个等待页面,并让浏览器重试(使用metarefresh或者JavaScript)return200'排队中,请稍后重试...';#或者返回一个静态页面#或者使用lua_block进行复杂处理}}```但是,这种方案并不是真正的排队,而是让客户端重试(或者等待客户端重试),这可能会增加客户端的等待时间,并且如果所有后端都过载,则客户端需要不断重试。因此,我们建议如果业务需要排队功能,应选择NginxPlus或HAProxy。总结回答:-配置max_conns:在upstream的server行中添加max_conns参数。-实现排队等待:在开源Nginx中没有直接支持,但可以通过以下方法:a)使用NginxPlus的queue指令。b)使用HAProxy的maxqueue参数。c)在开源Nginx中使用重试机制(proxy_next_upstream)和错误处理(error_page)来模拟,但效果有限。下面我们将按照上述思路组织回答。</think>### Nginx 配置 max_conns 与请求排队等待 #### 1. **配置 max_conns 限制连接数** 在 `upstream` 模块中,`max_conns` 参数用于限制单个后端服务器的最大并发连接数,防止过载。配置示例如下: ```nginx upstream api_server { server localhost:18080 max_conns=10; # 限制最大连接数为10 server localhost:63344 max_conns=15; # 限制最大连接数为15 } ``` - **作用**:当某台服务器的连接数达到 `max_conns` 时,Nginx 会停止向其分发新请求,避免后端过载[^3][^4]。 - **注意事项**: - 默认情况下,超出 `max_conns` 的请求会直接返回 **502 错误**(Bad Gateway)。 - 需配合 `proxy_pass` 使用: ```nginx location / { proxy_pass http://api_server; proxy_set_header Host $host; } ``` #### 2. **实现请求排队等待(开源版 Nginx)** 开源版 Nginx **不支持原生请求排队**,但可通过以下方案模拟排队效果: ##### 方案 1:使用重试机制(有限排队) 通过 `proxy_next_upstream` 将超限请求重定向到其他可用服务器: ```nginx upstream api_server { server localhost:18080 max_conns=10; server localhost:63344 max_conns=15; } location / { proxy_pass http://api_server; proxy_next_upstream error timeout http_502; # 当返回502时重试 proxy_next_upstream_tries 3; # 最多重试3次 proxy_next_upstream_timeout 10s; # 每次重试超时时间 } ``` - **效果**:当某台服务器达到 `max_conns` 返回 502 时,请求会尝试其他服务器或等待后重试。 - **缺点**:非严格排队,可能造成请求延迟或多次重试[^2]。 ##### 方案 2:结合限流模块(需扩展) 使用 `limit_req` 模块限制客户端请求速率,间接实现排队: ```nginx http { limit_req_zone $binary_remote_addr zone=req_queue:10m rate=5r/s; # 每秒5个请求 upstream api_server { server localhost:18080 max_conns=10; } location / { limit_req zone=req_queue burst=20; # 允许突发20个请求排队 limit_req_status 429; # 超出限流返回429 proxy_pass http://api_server; } } ``` - **效果**:超出 `rate` 的请求会被放入 `burst` 队列等待处理。 - **缺点**:队列作用于客户端请求速率,而非后端连接数[^2]。 #### 3. **完美解决方案:Nginx Plus** Nginx Plus 商业版提供原生排队功能,通过 `queue` 指令实现: ```nginx upstream api_server { server localhost:18080 max_conns=10; queue 100 timeout=30s; # 允许100个请求排队,超时30秒 } ``` - **效果**:当所有后端服务器均达到 `max_conns` 时,新请求进入队列等待,直到: - 有空闲服务器时被处理。 - 超过 `timeout` 时间返回错误(默认 `timeout=60s`)[^2][^4]。 --- ### 总结建议 - **基础防护**:使用 `max_conns` 防止单台后端过载。 - **开源排队**:优先采用 `proxy_next_upstream` 重试机制(方案1),或结合 `limit_req` 限流(方案2)。 - **生产高并发**:考虑 **Nginx Plus** 的 `queue` 功能(方案3),实现真正的请求排队。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值