nginx limit-req的一个注意点

要做一个很简单的功能。就是对整个nginx限流,因此也不需要定义好特别的变量

1
2
3
4
#整个nginx每秒请求数限制:
limit_req_zone allreq zone=allreq:10m rate=20000r/s;
limit_req_dry_run on;
limit_req zone=allreq burst=10 nodelay;

为了防止被误拦截,于是还特地加了limit_req_dry_run方法。这里就是限制整个nginx每秒20000次请求。超过了就返回503.

可观察了一天,发现居然还是要有超过的,虽然burst设置为10,可居然还是有超过的,最多的都超了20多。

这就很奇怪了,这个机器的并发根本不会到2万每秒的,难道这里必须写变量? 可也不对啊,这里检查也没有报错。那不会是nginx的bug,于是下载1.18.1的代码看了下

src/http/modules/ngx_http_limit_req_module.c文件的468行里是这样来的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14

excess = lr->excess - ctx->rate * ms / 1000 + 1000;

if (excess < 0) {
excess = 0;
}

*ep = excess;

if ((ngx_uint_t) excess > limit->burst) {
return NGX_BUSY;
}


而我们知道nginx的限流的原理是漏桶原理,这里就把秒换算成了毫秒来计算。20000每秒,换算成毫秒就是每毫秒不能超过20个,这个还是有可能,这个机器日常也有1000的qps,真保不齐哪一个毫秒超过20个的。

既然这样我就把burst的量加大一下,加到200个,这样每一毫秒肯定不会超了。

因此最终的配置就变成了

1
2
3
#整个nginx每秒请求数限制:
limit_req_zone allreq zone=allreq:10m rate=20000r/s;
limit_req zone=allreq burst=200 nodelay;