我正在尝试为我的网站设置一些动态速率限制,以在流量巨大时保护它。我知道在某些奇怪的情况下,我遇到了峰值(正常使用量可能会增加 10 倍,而正常使用量却会疯狂增加几个小时)。
以下是我尝试设置的方法:
limit_conn_zone $binary_remote_addr zone=addr:10m;
map $connections_active $response_rate {
~\b([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]\{2\}|9[0-8][0-9]|99[0-9]|1000)\b 0;
~\b(100[1-9]|10[1-9][0-9]|1[1-9][0-9]\{2\}|2000)\b 62k;
~\b(200[1-9]|20[1-9][0-9]|2[1-9][0-9]\{2\}|3000)\b 41k;
~\b(300[1-9]|30[1-9][0-9]|3[1-9][0-9]\{2\}|4000)\b 31k;
~\b(400[1-9]|40[1-9][0-9]|4[1-9][0-9]\{2\}|5000)\b 25k;
default 10k;
}
log_format x 'Current active connection: $connections_active , rate limit set to: $response_rate';
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
server {
limit_rate $response_rate;
access_log /var/log/nginx/access.log x;
listen 443 ssl http2;
listen [::]:443 ssl http2;
.................................................etc
我确实使用 loader.io 来测试它是否正常工作,而且看起来确实如此,因为日志很大,没有必要将其全部上传到 pastebin,所以我包括了相关部分:开始如下:
Current active connection: 1 , rate limit set to: 0
Current active connection: 2 , rate limit set to: 0
Current active connection: 916 , rate limit set to: 0
到这里一切都很好,稍后在日志中:
Current active connection: 1029 , rate limit set to: 62k
再次,这是正确的,因为如果活跃用户在 1000 到 2000 之间,则应该将限制设置为 62k,但是随后发生了这种情况:
Current active connection: 1126 , rate limit set to: 62k
Current active connection: 1246 , rate limit set to: 10k
在此阶段之后,速率限制保持在 10k:
Current active connection: 2 , rate limit set to: 10k
我做错了什么,为什么映射值没有更新?另外,为什么正则表达式求值从正确求值跳转到默认求值?
谢谢。
更新 1 暂时,在我找不到更好的解决方案之前,我停止使用 map,并且添加了一些 if 语句,但我更喜欢使用 map:
server {
set $response_rate 5k;
if ($connections_active ~ "\b([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|1000)\b")
{
set $response_rate 0;
}
if ($connections_active ~ "\b(100[1-9]|10[1-9][0-9]|1[1-9][0-9]{2}|2000)\b")
{
set $response_rate 62k;
}
if ($connections_active ~ "\b(200[1-9]|20[1-9][0-9]|2[1-9][0-9]{2}|3000)\b")
{
set $response_rate 41k;
}
if ($connections_active ~ "\b(300[1-9]|30[1-9][0-9]|3[1-9][0-9]{2}|4000)\b")
{
set $response_rate 32k;
}
if ($connections_active ~ "\b(400[1-9]|40[1-9][0-9]|4[1-9][0-9]{2}|5000)\b")
{
set $response_rate 25k;
}
if ($connections_active ~ "\b(500[1-9]|50[1-9][0-9]|5[1-9][0-9]{2}|6[0-9]{3}|7[0-4][0-9]{2}|7500)\b")
{
set $response_rate 10k;
}
# access_log /var/log/nginx/access.log x;
limit_rate $response_rate;
listen 443 ssl http2;
listen [::]:443 ssl http2;
...................etc
答案1
也许 REGEX 略有不同?0-999、1000-1999 等。
~\b([0-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9])\b 0;
~\b(1[0-8][0-9]{2}|19[0-8][0-9]|199[0-9])\b 62k;
~\b(2[0-8][0-9]{2}|29[0-8][0-9]|299[0-9])\b 41k;
~\b(3[0-8][0-9]{2}|39[0-8][0-9]|399[0-9])\b 31k;
~\b(4[0-8][0-9]{2}|29[0-8][0-9]|499[0-9])\b 25k;
default 10k;