【问题标题】:Multiple limit_req_zone with geo and map in nginxnginx中带有地理和地图的多个limit_req_zone
【发布时间】:2018-11-28 14:00:37
【问题描述】:

我在使用地图和地理模块定义 nginx 中的速率限制方面需要帮助。

我已经定义了 4 个案例。每种情况都应设置不同的速率限制:

geo $limited_ip {
            default                 0;
            1.1.1.1/24              1;
            2.2.2.2/24              2;
            3.3.3.3/24              3;
    }

我使用map模块将客户端的ip值传递给一个变量:

map $limited_ip $limited_ip_key {
            0 '';
            1 $binary_remote_addr;
            2 $binary_remote_addr;
            3 $binary_remote_addr;
    }

现在,我设置了 4 个限制区域。最后一个区域用于测试:

limit_req_zone $limited_ip_key zone=zone0:10m rate=100r/m;
limit_req_zone $limited_ip_key zone=zone1:10m rate=200r/m;
limit_req_zone $limited_ip_key zone=zone2:10m rate=500r/m;
limit_req_zone $limited_ip_key zone=zone3:10m rate=1r/m;

最后,我在 server{} 块中应用了限制:

limit_req zone=zone0 burst=10 nodelay;
limit_req zone=zone1 burst=10 nodelay;
limit_req zone=zone2 burst=10 nodelay;
limit_req zone=zone3 burst=1 nodelay;

配置测试如果ok,我重新加载nginx,也ok。使用 apache bench 工具 (ab) 锤击 nginx 服务器,看起来 zone3 总是匹配任何源 IP。为什么 geo 模块定义的其他掩码中的 IP 与 zone3 匹配?

日志:

*2757 limiting requests, excess: 1.697 by zone "zone3", client: 3.3.3.3, server: my.domain.com, request: "HEAD / HTTP/1.0", host: "my.domain.com"
*29449 limiting requests, excess: 1.958 by zone "zone3", client: 2.2.2.2, server: my.domain.com, request: "HEAD / HTTP/2.0", host: "my.domain.com"

我找到的所有结果都定义了大约 2 个区域,我找不到更多区域的示例。或许这种方式不可行?

谢谢

【问题讨论】:

    标签: nginx rate-limiting


    【解决方案1】:

    我今天正在搜索相同的配置,但也找不到超过 2 个区域的示例。所以理论上应该是这样的(我还没有尝试过):

    geo $limited_ip {
                default                 0;
                1.1.1.1/24              1;
                2.2.2.2/24              2;
                3.3.3.3/24              3;
        }
    
    
    map $limited_ip $limited_ip_key0 {
            0 $binary_remote_addr;
            1 '';
            2 '';
            3 '';
    }
    
    map $limited_ip $limited_ip_key1 {
            0 '';
            1 $binary_remote_addr;
            2 '';
            3 '';
    }
    
    map $limited_ip $limited_ip_key2 {
            0 '';
            1 '';
            2 $binary_remote_addr;
            3 '';
    }
    
    map $limited_ip $limited_ip_key3 {
            0 '';
            1 '';
            2 '';
            3 $binary_remote_addr;
    }
    
    limit_req_zone $limited_ip_key0 zone=zone0:10m rate=100r/m;
    limit_req_zone $limited_ip_key1 zone=zone1:10m rate=200r/m;
    limit_req_zone $limited_ip_key2 zone=zone2:10m rate=500r/m;
    limit_req_zone $limited_ip_key3 zone=zone3:10m rate=1r/m;
    
    
    limit_req zone=zone0 burst=10 nodelay;
    limit_req zone=zone1 burst=10 nodelay;
    limit_req zone=zone2 burst=10 nodelay;
    limit_req zone=zone3 burst=1 nodelay;
    

    解释:

    a) 如果 IP 不是定义的 3 个中的任何一个,则

    $limited_ip_key0 = $binary_remote_addr
    $limited_ip_key1 = ''
    $limited_ip_key2 = ''
    $limited_ip_key3 = ''
    

    因此将仅匹配 zone0,并应用 100r/m 的速率限制

    b) 如果 IP 是 1.1.1.1/24

    $limited_ip_key0 = ''
    $limited_ip_key1 = $binary_remote_addr
    $limited_ip_key2 = ''
    $limited_ip_key3 = ''
    

    因此将仅匹配 zone1,并应用 200r/m 的速率限制

    c) 如果 IP 是 2.2.2.2/24

    $limited_ip_key0 = ''
    $limited_ip_key1 = ''
    $limited_ip_key2 = $binary_remote_addr
    $limited_ip_key3 = ''
    

    因此将仅匹配 zone2,并应用 500r/m 的速率限制

    d) 如果 IP 是 3.3.3.3/24

    $limited_ip_key0 = ''
    $limited_ip_key1 = ''
    $limited_ip_key2 = ''
    $limited_ip_key3 = $binary_remote_addr
    

    因此将仅匹配 zone3,并应用 1r/m 的速率限制

    这是一个自动创建所需区域的 php 脚本,因此您可以轻松管理更多区域和 ips

    <?php
    
    list($mapString, $zonesString, $zonesArray) = createZones(
        "myendpoint",
        array(
            "default"=>array(
                "zoneSize"=>"10m",
                "rate"=>"10r/s",
                "burst"=>"100",
                "options"=>""
            ),
            "zone1"=>array(
                "ips"=>array(
                    "11.11.11.11/32",
                    "1.1.1.1/24"
                ),
                "zoneSize"=>"10m",
                "rate"=>"10r/s",
                "burst"=>"100",
                "options"=>""
            ),
             "zone2"=>array(
                "ips"=>array(
                    "22.22.22.22/32",
                    "2.2.2.2/24"
                ),
                "zoneSize"=>"10m",
                "rate"=>"20r/s",
                "burst"=>"100",
                "options"=>"nodelay"
            ),
            "zone3"=>array(
                "ips"=>array(
                    "33.33.33.33/32",
                    "3.3.3.3/24"
                ),
                "zoneSize"=>"10m",
                "rate"=>"30r/s",
                "burst"=>"100",
                "options"=>""
            ),
        )
    );
    
    echo "# Define the ips and maps\n$mapString\n#Define the zones\n$zonesString\n\n";
    
    echo "\t# limit directives to be placed inside the location section\n";
    foreach ($zonesArray as $zoneName=>$zoneString) {
        echo   "\t$zoneString\n";
    }
    
    
    
    function createZones($endpointPrefix,$zones) {
    
        $mapString0='geo $'.$endpointPrefix.' {'."\n\t\tdefault\t0;";
    
        $mapString1='';
        $zonesString='';
        $zonesArray=array();
    
        $zoneNum=0;
        foreach ($zones as $zoneName=>$params) {
    
            $zoneName=strtolower($zoneName);
            if ($zoneName!='default') {
                $zoneNum++;
                foreach($params['ips'] as $ip) {
                    $mapString0.="\n\t\t$ip\t$zoneNum;";
                }
            }
    
        }
        $mapString0.="\n}\n";
    
        $zoneNumTotal=$zoneNum;
        // now that we now the total zones we can create the maps
        $zoneNum=0;
        foreach ($zones as $zoneName=>$params) {
    
            $zoneName=strtolower($zoneName);
            $mapString1.='map $'.$endpointPrefix.' $'.$endpointPrefix.'_key_'.$zoneName.' {';
    
            for($zoneNumTemp=0;$zoneNumTemp<=$zoneNumTotal;$zoneNumTemp++) {
                if ($zoneNum==$zoneNumTemp) {
                    $mapString1.="\n\t\t$zoneNumTemp\t\$binary_remote_addr;";
                } else {
                    $mapString1.="\n\t\t$zoneNumTemp\t'';";
                }
            }
            $mapString1.="\n}\n\n";
    
            $zoneNum++;
        }
    
        // now create the actual zones string
        foreach ($zones as $zoneName=>$params) {
            $zoneName=strtolower($zoneName);
            $zonesString.="\n";
            if ( isset( $params['ips']) ) {
                foreach ($params['ips'] as $ip) {
                    $zonesString .= "# $ip\n";
                }
            }
            $zonesString.='limit_req_zone $'.$endpointPrefix.'_key_'.$zoneName.' zone='.$endpointPrefix.'_'.$zoneName.':'.$params['zoneSize'].' rate='.$params['rate'].';';
            $zonesString.="\n";
        }
    
        // now create the limits that should be applied inside the location sections
    
        foreach ($zones as $zoneName=>$params) {
            $zoneName=strtolower($zoneName);
            $zonesArray[$zoneName]='limit_req zone='.$endpointPrefix.'_'.$zoneName;
    
            if ($params['burst']) {
                $zonesArray[$zoneName].=' burst='.$params['burst'];
            }
            if ($params['options']) {
                $zonesArray[$zoneName].=' '.$params['options'];
            }
    
        }
    
        return array($mapString0."\n".$mapString1, $zonesString,$zonesArray);
    }
    

    执行上述脚本时会产生:

    # Define the ips and maps
    geo $myendpoint {
                    default 0;
                    11.11.11.11/32  1;
                    1.1.1.1/24      1;
                    22.22.22.22/32  2;
                    2.2.2.2/24      2;
                    33.33.33.33/32  3;
                    3.3.3.3/24      3;
    }
    
    map $myendpoint $myendpoint_key_default {
                    0       $binary_remote_addr;
                    1       '';
                    2       '';
                    3       '';
    }
    
    map $myendpoint $myendpoint_key_zone1 {
                    0       '';
                    1       $binary_remote_addr;
                    2       '';
                    3       '';
    }
    
    map $myendpoint $myendpoint_key_zone2 {
                    0       '';
                    1       '';
                    2       $binary_remote_addr;
                    3       '';
    }
    
    map $myendpoint $myendpoint_key_zone3 {
                    0       '';
                    1       '';
                    2       '';
                    3       $binary_remote_addr;
    }
    
    
    #Define the zones
    
    limit_req_zone $myendpoint_key_default zone=myendpoint_default:10m rate=10r/s;
    
    # 11.11.11.11/32
    # 1.1.1.1/24
    limit_req_zone $myendpoint_key_zone1 zone=myendpoint_zone1:10m rate=10r/s;
    
    # 22.22.22.22/32
    # 2.2.2.2/24
    limit_req_zone $myendpoint_key_zone2 zone=myendpoint_zone2:10m rate=20r/s;
    
    # 33.33.33.33/32
    # 3.3.3.3/24
    limit_req_zone $myendpoint_key_zone3 zone=myendpoint_zone3:10m rate=30r/s;
    
    
            # limit directives to be placed inside the location section
            limit_req zone=myendpoint_default burst=100
            limit_req zone=myendpoint_zone1 burst=100
            limit_req zone=myendpoint_zone2 burst=100 nodelay
            limit_req zone=myendpoint_zone3 burst=100
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-03
      • 1970-01-01
      • 2017-06-12
      • 1970-01-01
      • 1970-01-01
      • 2020-12-19
      相关资源
      最近更新 更多