В 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