limit_req отличается зонами по времени суток - PullRequest
0 голосов
/ 13 июня 2018

Я хочу ограничить количество запросов к моему сервису в зависимости от времени суток.
Это должно быть 4 об / с ночью (21:00 - 06:59) и 1 об / с днем ​​(07:00-20: 59).
У меня может быть 2 разных req_limit_zone типа

limit_req_zone $server_name zone=day:1m rate=1r/s;
limit_req_zone $server_name zone=night:1m rate=4r/s;

, но как я могу различать их в limit_req в зависимости от времени дня?

Служба, стоящая за nginx, является оболочкой API для другой службы с ограничениями, описанными выше.Мой сервис написан на Flask-RESTful, запускается uWSGI с несколькими процессами, поэтому было бы довольно болезненно реализовать ограничивающую логику и синхронизировать ее между процессами с чем-то вроде redis.

Можно ли настроить nginx таким образом?
Если это не так, есть ли какие-нибудь общие обходные пути?Как другие сервисы решают эту задачу?
Чтобы быть более конкретным, это должно быть утечка, поэтому клиенты просто ждут ответа без каких-либо ошибок, таких как HTTP 429 Too Many Requests.

1 Ответ

0 голосов
/ 13 июня 2018

Ответ

Ключ должен связать limit_req_zone и map.О них есть две соответствующие заметки в документах. map :

default value

устанавливает результирующее значение, если исходное значение не соответствует ни одному из указанных вариантов.Если default не указано, результирующим значением по умолчанию будет пустая строка .

и limit_req_zone :

limit_req_zone key zone = name: size rate = rate;

Устанавливает параметры для зоны общей памяти, в которой будут храниться состояния для различных клавиш,В частности, государство хранит текущее количество чрезмерных запросов.key может содержать текст, переменные и их комбинацию. Запросы с пустым значением ключа не учитываются .

Таким образом, можно просто использовать и день и ночь limit_req_zone с $server_name как ключ , если он должен работать, и с пустой строкой, если он не должен.И map вернет либо $server_name, либо пустую строку в зависимости от времени суток.

map $date_gmt $day {  
    # 07:00-20:59 GMT  
    ~(0[7-9]|1[0-9]|20):[0-5][0-9]:[0-5][0-9] $server_name;  
}

map $date_gmt $night {  
    # 21:00-06:59 GMT  
    ~(2[1-4]|0[0-6]):[0-5][0-9]:[0-5][0-9] $server_name;  
}

limit_req_zone $day zone=day_zone:1m rate=1r/s;
limit_req_zone $night zone=night_zone:1m rate=4r/s;

...

limit_req zone=day_zone burst=100;
limit_req zone=night_zone burst=100;

Некоторые заметки о req_limit

При первой попытке я попыталсяиспользуйте сопоставленную переменную в limit_req, но nginx не понимает такой синтаксис.Более того, на первый взгляд nginx -s reload работал без проблем, но на самом деле перезагрузки не было, и только service nginx restart показывал ошибку (версия nginx: 1.12.2).Поэтому я хотел бы показать, как один не должен делать :

limit_req_zone $server_name zone=day:1m rate=1r/s;
limit_req_zone $server_name zone=night:1m rate=4r/s;

map $date_gmt $time_of_day {  
    ~(0[7-9]|1[0-9]|20):[0-5][0-9]:[0-5][0-9] day;  
    ~(2[1-4]|0[0-6]):[0-5][0-9]:[0-5][0-9] night;  
}

...

limit_req zone=$time_of_day burst=100;  

Несколько замечаний о производительности

Это не таклучшее решение из-за двойной проверки времени на каждый запрос.Существует возможность иметь два отдельных конфига nginx и переключать их чем-то вроде cron.Это было бы уродливо и глючно, потому что вы должны помнить, что нужно редактировать две конфигурации, но это будет работать быстрее;Я думаю, что этот вариант следует использовать в качестве крайней меры.Если есть возможность горизонтального масштабирования, лучше балансировать нагрузку на несколько серверов.В моем случае это не имеет большого значения: сервис получает около 8 тыс. Запросов в час (2,2 об / с).

...