V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
seedhk
V2EX  ›  程序员

关于 nginx 中 limit_req_zone 模块的 burst 的疑惑

  •  
  •   seedhk · 96 天前 · 1005 次点击
    这是一个创建于 96 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码如下:

    http{
    
       limit_req_zone $binary_remote_addr zone=mylimit:1m rate=6r/m;
       
       server {
          listen 80;
          ......
          location / {
             limit_req zone=mylimit burst=5;
             proxy_pass http://www.baidu.com;
          }
       }
    }
    

    对于 burst ,nginx 给的解释是:

    https://blog.nginx.org/blog/rate-limiting-nginx#:~:text=The%20burst%20parameter%20defines,requests%20go%20over%C2%A020.

    摘录如下:

    The burst parameter defines how many requests a client can make in excess of the rate specified by the zone (with our sample mylimit zone, the rate limit is 10 requests per second, or 1 every 100ms). A request that arrives sooner than 100ms after the previous one is put in a queue, and here we are setting the queue size to 20.
    
    That means if 21 requests arrive from a given IP address simultaneously, NGINX forwards the first one to the upstream server group immediately and puts the remaining 20 in the queue. It then forwards a queued request every 100ms, and returns 503 to the client only if an incoming request makes the number of queued requests go over 20.
    

    结合代码和这段文字,我对 burst 的理解是:

    6r/m:以每 1 分钟为一个时间阶段,将这 1 分钟分为 6 段,即每 10s 最多接收 1 个请求,该 10s 内的多余请求将会被返回 503 ;

    burst=5:突发队列长度=5 。以每 1 分钟为一个时间阶段,在这 1 分钟内,该队列最多只能接受 5 个请求,即使该队列内的请求已经被处理,也不会往队列里新增新的请求,直到下 1 分钟到来。

    测试

    测试工具:jmeter
    测试线程数:120
    测试时间(ramp-up):120s
    循环次数:1

    预期结果:

    在 120s 内,一共发起了 120 个请求,其中请求成功 22 个(6+6+5+5),其余返回 503 ;

    实际测试结果:

    在 120s 内,一共发起了 120 个请求,其中请求成功 17 个(6+6+5),其余返回 503 ;

    为什么少了 5 个请求,希望大佬们为我指点下,谢谢~

    7 条回复    2024-08-22 14:36:20 +08:00
    kk2syc
        1
    kk2syc  
       96 天前
    120s 内,最后 5 个在队列里等待。
    ----
    假定 rate=10r/s 时,将 1s 拆成 10 份,即每 100ms 可处理 1 个请求。
    当 burst=5 ,若同时有 6 个请求到达,Nginx 会立刻处理第 1 个请求,剩余 5 个请求将放入队列,然后每隔 100ms 从队列中获取一个请求进行处理。
    若请求数大于 6 ,将拒绝处理多余的请求,直接返回 503 。
    同时,队列中的 5 个请求虽然每 100ms 会处理一个,但第 5 个请求却需要等待 5 * 100ms 即 500ms 。
    seedhk
        2
    seedhk  
    OP
       96 天前
    @kk2syc 感谢回答,确实是这样

    假设 rate=10r/s ,burst=5 。且又有 6 个请求过来了,那么会被执行的有多少个,会被拒绝的有多少个?
    kk2syc
        3
    kk2syc  
       96 天前
    @seedhk 执行 6 个,拒绝 0 个 ( 1 个立即执行,5 个放入队列)

    来 10 个,执行 6 个,拒绝 4 个
    seedhk
        4
    seedhk  
    OP
       96 天前
    @kk2syc
    我的理解也是这样,但是我测试的结果是,第二次请求,没有使用到队列

    这里要先声明一个问题:
    nginx 是如何区分这是第一次还是第二次请求(你提供的例子),或者第一次和第二次请求是放一起的(我测试的例子)
    kk2syc
        5
    kk2syc  
       96 天前
    @seedhk 嗷,我明白你说的点了,rate 表示允许相同标识客户端的并发访问频次
    我用 `ab -n 10 -c 10` 测是没问题的
    ----
    翻看源码,src/http/modules/ngx_http_limit_req_module.c

    ```
    ms = (ngx_msec_int_t) (now - lr->last);
    excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000;
    if (excess < 0) {
        excess = 0;
    }
    *ep = excess;
    if ((ngx_uint_t) excess > limit->burst) {
       return NGX_BUSY;
    }
    if (account) {
        lr->excess = excess;
        lr->last = now;
       return NGX_OK;
    }
    ```
    所以,数量计算公式,频率是 rate(r/s),每次请求距离上次请求 T(ms),burst 为 b

    skyrim61
        6
    skyrim61  
       95 天前
    复杂
    seedhk
        7
    seedhk  
    OP
       95 天前
    @kk2syc 学习了,谢谢~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1261 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 18:10 · PVG 02:10 · LAX 10:10 · JFK 13:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.