1

我需要帮助来定义使用地图和地理模块的 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。为什么来自其他掩码的 IP 由 geo 模块匹配 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 个区域,我找不到更多区域的示例。也许不可能这样做?

谢谢

4

1 回答 1

0

我今天正在搜索相同的配置,也找不到超过 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 脚本,因此您可以轻松管理更多区域和 ip

<?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
于 2019-01-18T19:06:38.110 回答