В Nginx есть возможность ограничить количество соединений с одного адреса(модуль ngx_http_limit_conn_module) и ограничить количество запросов в единицу времени с одного адреса (модуль ngx_http_limit_req_module)
|
1 |
ngx_http_limit_conn_module |
— позволяет ограничить число соединений по заданному ключу, в частности, число соединений с одного IP-адреса.
|
1 |
ngx_http_limit_req_module |
– позволяет ограничить скорость обработки запросов по заданному ключу, в частности, скорость обработки запросов, поступающих с одного IP-адреса
Ограничение количества соединений с одного адреса
|
1 |
limit_conn_zone |
Задаёт параметры зоны разделяемой памяти, которая хранит состояние для разных значений ключа. Состояние в частности содержит текущее число соединений
|
1 |
limit_conn_log_level |
( по умолчанию limit_conn_log_level error;)
Задаёт желаемый уровень записи в лог случаев ограничения числа соединений.
|
1 |
limit_conn_status |
(По умолчанию limit_conn_status 503;)
Позволяет переопределить код ответа, используемый при отклонении запросов.
В секции http файла nginx.conf
Задаем ключ, к которому относятся ограничения ($binary_remote_addr), зону с именем connection и размер зоны 10 мегабайт
Изменяем уровень протоколирования ограничений соединения с error на warn
|
1 |
# nano /etc/nginx/nginx.conf |
|
1 2 3 4 5 6 |
http { …………… limit_conn_zone $binary_remote_addr zone=connections:10m; limit_conn_log_level warn; ……………… } |
|
1 |
limit_conn |
Задаёт зону разделяемой памяти и максимально допустимое число соединений для одного значения ключа. При превышении этого числа в ответ на запрос сервер вернёт ошибку 503 (Service Temporarily Unavailable)
Ограничиваем кол-во соединений с одного адреса – не более 8 в конфигурационном файле виртуального хоста
|
1 |
# nano /etc/nginx/conf.d/<virtualhost>.conf |
|
1 2 3 4 5 |
server { .................................. limit_conn connections 8; .................................. } |
|
1 |
# /etc/init.d/nginx configtest |
|
1 |
# /etc/init.d/nginx reload |
Ограничение количества запросов в секунду с одного адреса
|
1 |
limit_req_zone |
Задаёт параметры зоны разделяемой памяти, которая хранит состояние для разных значений ключа. Состояние в частности хранит текущее число избыточных запросов.
|
1 |
limit_req_log_level |
( по умолчанию limit_conn_log_level error;)
Задаёт желаемый уровень записи в лог случаев отказа в обработке запросов при превышении скорости и случаев задержек при обработке запроса. Задержки записываются в лог с уровнем на единицу меньшим, чем отказы, например, если указано limit_req_log_level warn, то задержки будут записываться в лог на уровне notice.
|
1 |
limit_req_status |
(по умолчанию limit_req_status 503; )
Позволяет переопределить код ответа, используемый при отклонении запросов.
Очень полезная утилита для запуска dry-run режима по rate limit
Эта директива появилась в Nginx версии 1.17.1
|
1 |
limit_req_dry_run |
(по умолчанию limit_req_dry_run off;)
Включает режим пробного запуска. В данном режиме скорость обработки запросов не ограничивается, однако в зоне разделяемой памяти текущее число избыточных запросов учитывается как обычно.
Т.е отклонения запросов по факту не происходит, но выполняется полный расчет кол-ва соединений и все превышающие лимиты запросы записываются в лог-файл
Ограничение количества запросов в секунду с одного адреса — не более 5 со всплесками не более 10 запросов
Изменяем уровень протоколирования ограничений соединения с error на warn
В секции http файла nginx.conf
|
1 2 3 4 5 6 |
http { ………………… limit_req_zone $binary_remote_addr zone=requests:10m rate=5r/s; limit_req_log_level warn; ……… } |
|
1 |
limit_req |
Задаёт зону разделяемой памяти (zone) и максимальный размер всплеска запросов (burst). Если скорость поступления запросов превышает описанную в зоне, то их обработка задерживается так, чтобы запросы обрабатывались с заданной скоростью. Избыточные запросы задерживаются до тех пор, пока их число не превысит максимальный размер всплеска. При превышении запрос завершается с ошибкой 503 (Service Temporarily Unavailable). По умолчанию максимальный размер всплеска равен нулю
В конфигурационном файле виртуального хоста
|
1 |
# nano /etc/nginx/conf.d/<virtualhost>.conf |
|
1 2 3 4 5 |
server { .................................. limit_req zone=requests burst=10; .................................. } |
Если же избыточные запросы в пределах лимита всплесков задерживать не требуется, то следует использовать параметр nodelay:
|
1 |
limit_req zone=requests burst=10 nodelay; |
|
1 |
# /etc/init.d/nginx configtest |
|
1 |
# /etc/init.d/nginx reload |
Ограничения можно устанавливать,как для всего виртуального хоста (в директиве server), так и для отдельных location
Например, при связке Nginx+PHP-FPM можно устанавливать ограничения на количество запросов в секунду к php-файлам
В конфигурационном файле виртуального хоста
|
1 |
# nano /etc/nginx/conf.d/<virtualhost>.conf |
|
1 2 3 4 5 6 7 |
server { …………………….. location ~ \.php$ { limit_req zone=requests burst=10; ……………… } } |
Тестировать можно через ab или siege утилиты
# siege -v -b -r 1 -c 10 https://mysite.com/index.php
# ab -n 20 -c 20 https://mysite.com/index.php
Для определенных IP-адресов, подсетей можно отключить rate limit
Для этого в http -секции добавляем блок
|
1 2 3 4 5 6 7 8 9 |
geo $limit { default 0; include sites-available/rate-limit-ips.txt; } map $limit $limit_key { 1 ""; 0 $binary_remote_addr; } |
Вместо подключения файла с помощью директивы include можно перечислять список IP-адресов/сетей в таком же формате, как это указано в файле
sites-available/rate-limit-ips.txt
|
1 |
# cat sites-available/rate-limit-ips.txt; |
|
1 2 3 4 5 6 7 8 9 10 |
### Localhost 127.0.0.1 1; ### Internal networks 10.0.0.0/8 1; 192.168.0.0/16 1; 172.16.0.0/12 1; ### External IP-address 111.111.111.111 1; |
Далее приведу перевод отличной, на мой взгляд, статьи
оригинал
https://www.freecodecamp.org/news/nginx-rate-limiting-in-a-nutshell-128fe9e0126c
перевод
https://habr.com/ru/company/southbridge/blog/329876/
Директивы NGINX по ограничению скорости обработки запросов
В этой статье мы будем говорить о ngx_http_limit_req_module, в котором реализованы директивы limit_req_zone, limit_req, limit_req_status и limit_req_level. Они позволяют управлять значением кода состояния HTTP-запроса для отклоненных (rejected) запросов, а также логированием этих отказов.
Чаще всего путаются именно в логике отклонения запроса.
Сначала нужно разобраться с директивой limit_req, которой требуется параметр zone. У него также есть необязательные параметры burst и nodelay.
Здесь используются следующие концепции:
zone определяет «ведро» (bucket) — разделяемое пространство, в котором считаются входящие запросы. Все запросы, попавшие в одно «ведро», будут посчитаны и обработаны в его разрезе. Этим достигается возможность установки ограничений на основе URL, IP-адресов и т. д.
burst — необязательный параметр. Будучи установленным, он определяет количество запросов, которое может быть обработано сверх установленного базового ограничения скорости. Важно понимать, что burst — это абсолютная величина количества запросов, а не скорость.
nodelay — также необязательный параметр, который используется совместно с burst. Ниже мы разберемся, зачем он нужен.
Каким образом NGINX принимает решение о принятии или отклонении запроса?
При настройке зоны задается ее скорость. Например, при 300r/m будет принято 300 запросов в минуту, а при 5r/s — 5 запросов в секунду.
Примеры директив:
|
1 2 |
limit_req_zone $request_uri zone=zone1:10m rate=300r/m; limit_req_zone $request_uri zone=zone2:10m rate=5/s; |
Важно понимать, что эти две зоны имеют одинаковые лимиты. С помощью параметра rate NGINX рассчитывает частоту и, соответственно, интервал, после которого можно принять новый запрос. В данном случае NGINX будет использовать алгоритм под названием «дырявое ведро» (leaky bucket).
Для NGINX 300r/m и 5r/s одинаковы: он будет пропускать один запрос каждые 0,2 с. В данном случае NGINX каждые 0,2 секунды будет устанавливать флаг, разрешающий прием запроса. Когда приходит подходящий для этой зоны запрос, NGINX снимает флаг и обрабатывает запрос. Если приходит очередной запрос, а таймер, считающий время между пакетами, еще не сработал, запрос будет отклонен с кодом состояния 503. Если время истекло, а флаг уже установлен в разрешающее прием значение, никаких действий выполнено не будет.
Нужны ли ограничение скорости обработки запросов и шейпинг трафика?
Поговорим о параметре burst. Представьте, что флаг, о котором мы говорили выше, может принимать значения больше единицы. В этом случае он будет отражать максимальное количество запросов, которые NGINX должен пропустить в рамках одной пачки (burst).
Теперь это уже не «дырявое ведро», «маркерная корзина» (token bucket). Параметр rate определяет временной интервал между запросами, но мы имеем дело не с токеном типа true/false, а со счетчиком от 0 до 1 + burst Счетчик увеличивается каждый раз, когда проходит рассчитанный интервал времени (срабатывает таймер), достигая максимального значения в b+1. Напомню еще раз: burst — это количество запросов, а не скорость их пропускания.
Когда приходит новый запрос, NGINX проверяет доступность токена (счетчик > 0). Если токен недоступен, запрос отклоняется. В противном случае запрос принимается и будет обработан, а токен считается израсходованным (счетчик уменьшается на один).
Хорошо, если есть неизрасходованные burst-токены, NGINX примет запрос. Но когда он его обработает?
Мы установили лимит в 5r/s, при этом NGINX примет запросы сверх нормы, если есть доступные burst-токены, но отложит их обработку таким образом, чтобы выдержать установленную скорость. То есть эти burst-запросы будут обработаны с некоторой задержкой или завершатся по таймауту.
Другими словами, NGINX не превысит установленный для зоны лимит, а поставит дополнительные запросы в очередь и обработает их с некоторой задержкой.
Приведем простой пример: скажем, у нас установлен лимит 1r/s и burst=3. Что будет, если NGINX получит сразу 5 запросов?
Первый будет принят и обработан.
Поскольку разрешено не больше 1+3, один запрос будет сразу отклонен с кодом состояния 503.
Три оставшихся будут обработаны один за другим, но не мгновенно. NGINX пропустит их со скоростью 1r/s, оставаясь в рамках установленного лимита, а также при условии, что не будут поступать новые запросы, которые также используют квоту. Когда очередь опустеет, счетчик пачки (burst counter) снова начнет увеличиваться (маркерная корзина начнет наполняться).
В случае использования NGINX в качестве прокси-сервера расположенные за ним сервисы будут получать запросы со скоростью 1r/s и ничего не узнают о всплесках трафика, сглаженных прокси-сервером.
Итак, мы только что настроили шейпинг трафика, применив задержки для управления всплесками запросов и выравнивания потока данных.
nodelay
nodelay говорит NGINX, что он должен принимать пакеты в рамках окна, определенного значением burst, и сразу их обрабатывать (так же как и обычные запросы).
В результате всплески трафика все же будут достигать сервисов, расположенных за NGINX, но эти всплески будут ограничены значением burst.
Источник:
https://habr.com/ru/company/southbridge/blog/329876
https://www.freecodecamp.org/news/nginx-rate-limiting-in-a-nutshell-128fe9e0126c
http://nginx.org/ru/docs/http/ngx_http_limit_conn_module.html
http://nginx.org/ru/docs/http/ngx_http_limit_req_module.html

Октябрь 11th, 2014
Evgeniy Kamenev
Опубликовано в рубрике
Метки: