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

limit_req_zone 的使用疑问

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

    今天在使用 NGINX 的 limit_req_zone 时,发现统计出来的数据和过滤结果不一致的问题,情况如下:


    一、过滤:

    nginx 配置文件添加:

    limit_req_zone $binary_remote_addr zone=mylimit:100m rate=2000r/s;
    

    location / {} 中添加:

    limit_req zone=mylimit  burst=1000;
    

    重启 nginx 后,在 error.log 的日志中,发现了大量的这样的日志:

    2024/07/08 10:13:47 [error] 30#30: *75739 limiting requests, excess: 1.000 by zone "mylimit", client: x.x.x.x, server: xxx-zj.cn, request: "POST /rela/getid HTTP/1.1", host: "xxx-zj.cn",
    

    那么问题就来了,公司的访问量绝对不会高到 2000R/S ,更别说单个 IP 了。因此采用了两种方法统计了一下请求量


    二、统计:

    1.通过 grep 日志文件中的每一秒,wc -l 汇总数量:

    cat access.log |grep "\[08/Jul/2024:10:13:47" | wc -l 
    

    结果是 178 ,在统计几个,也都是 200+ 300+的数量,绝对不超过 1000


    2.通过 nginx_status 判断

    写一个脚本,统计 10s 内的 http://127.0.0.1/nginx_status ,并相减,求每秒的 requests

    for i in {1..10}
    do
        # 获取当前的请求数
        status=$(curl -s http://127.0.0.1/nginx_status)
        current_requests=$(echo "$status" | grep 'server accepts handled requests' -A 1 | tail -n 1 | awk '{print $3}')
        
        # 将当前请求数存储到数组中
        requests+=($current_requests)
        
        # 等待 1 秒
        sleep 1
    done
    
    #### 计算每秒请求数的差值
    echo "Requests difference per second:"
    for (( i=1; i<${#requests[@]}; i++ ))
    do
        diff=$((requests[i] - requests[i-1]))
        echo "Second $i: $diff requests"
    done
    

    运行脚本后,输出:
    Requests difference per second:
    Second 1: 258 requests
    Second 2: 325 requests
    Second 3: 334 requests
    Second 4: 300 requests

    ...省略

    结果也都是只有几百,远远没有到达 2000 的过滤阈值,请问大佬么,这是为什么?

    5 条回复    2024-07-09 10:18:56 +08:00
    seedhk
        1
    seedhk  
    OP
       138 天前
    补充一下:
    rate=2000r/s ,代表每 1s 最多允许 2000 个请求,也就意味着每 0.5 微秒最多只允许通过 1 个请求,如果在 0.5 微秒有两个请求到达,是会触发限制。但是添加了 burst=1000 ,等于有个大小为 1000 的队列。相当于每 0.5 微秒最多允许通过 1+1000 个请求,按照业务和下面的统计来分析也是不可能的,难道是因为 burst 提供的队列是所有 ip 共用的吗?

    请大佬们指教
    abolast
        2
    abolast  
       138 天前
    2000 不是禁止阈值么,每秒超过这个值就等待下一秒呗,burst 是突变值,应该是 rate 的几倍而不是小于。
    如果要测试的话,应该是压测超过 2000 ,然后再看看是访问否有突破 2000 ,然后再超过 burst ,看看具体效果是多少。
    tip:如果是有长轮询这种,那么一个客户端可能代表了好几个请求,但是访问量只记录了一个
    abolast
        3
    abolast  
       138 天前
    刚才和同事讨论了一下,burst 是突变值,是正常速率 rate 之后的限速速率数量,burst 可以小于 rate ,当总请求超过 rate+burst 之后,是返回一个 503
    seedhk
        4
    seedhk  
    OP
       138 天前
    @abolast 是的,总请求超过 rate+burst 之后,是返回一个 503 。但是我上面经过测试发现即使 rate=2000r/s ,brust=2000 。这样设置的情况下,仍然会比较频繁出现 limiting requests 的日志。但是从第二部分的测试和实际业务的情况来看,应该是不会出现这种情况的,请问这是为啥?
    abolast
        5
    abolast  
       138 天前
    1s 太短,如果是 600/m 的话,是会被分为 60 等分,每 1s 只能通过 10 个请求,超过 10 就等待下一秒。我不知道 1s 会是什么逻辑,这个可能得去看源码是怎么写的了。你应该只用简单的请求来测试 limit_req_zone 的效果,如果是有长轮询,websocket 这种,可能是访问记录数量和实际请求数不一致
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1116 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 23:35 · PVG 07:35 · LAX 15:35 · JFK 18:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.