Привет, Хабр!

Сегодня рассмотрим, как настроить полноценный traffic shaping в Nginx для сложных случаев, включая HTTP/2.

С появлением HTTP/2 управление трафиком стало ещё сложнее из-за его особенностей:

  • Мультиплексирование: Несколько запросов могут выполняться по одному соединению одновременно.

  • Сжатие заголовков: Использование HPACK для сжатия заголовков может влиять на скорость передачи.

  • Приоритизация потоков: Клиенты могут устанавливать приоритеты для разных потоков.

Директивы Traffic Shaping в Nginx

Директива limit_rate

Ограничивает скорость передачи ответа клиенту.

limit_rate rate;
location /downloads/ {
    limit_rate 100k; # Ограничиваем скорость до 100 кБ/с
}

Эта директива устанавливает максимальную скорость передачи данных клиенту. Полезно для ограничения скорости загрузки больших файлов.

Директива limit_rate_after

Начинает ограничивать скорость после передачи определённого объёма данных.

limit_rate_after size;
location /videos/ {
    limit_rate_after 5m; # Начинаем ограничивать после 5 МБ
    limit_rate 500k;     # Ограничиваем скорость до 500 кБ/с
}

Можно использовать, когда нужно дать пользователю быстро начать загрузку, а затем ограничить скорость, чтобы не перегружать канал.

Модуль ngx_http_limit_req_module

Ограничивает количество запросов в секунду от одного клиента.

limit_req_zone key zone=name:size rate=rate;
  • key: Уникальный идентификатор клиента (обычно IP-адрес).

  • zone: Имя и размер памяти для хранения данных.

  • rate: Скорость запросов (например, 10r/s для 10 запросов в секунду).

Пример настройки:

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;

    server {
        location /api/ {
            limit_req zone=mylimit burst=10 nodelay;
            # burst=10 позволяет временно превышать лимит на 10 запросов
            # nodelay немедленно отклоняет лишние запросы
        }
    }
}

Эта настройка позволяет защитить API от перегрузки.

Модуль ngx_http_limit_conn_module

Ограничивает количество одновременных соединений с одним клиентом.

limit_conn_zone key zone=name:size;
http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    server {
        location /download/ {
            limit_conn addr 1; # Разрешаем только 1 соединение с одного IP
        }
    }
}

Хорошо для предотвращения одновременной загрузки нескольких файлов одним пользователем.

Примеры использования

Ограничение скорости для HTTP/2

В HTTP/2 все запросы идут по одному соединению, поэтому limit_rate будет применяться ко всем потокам сразу.

Будем использовать директиву limit_rate внутри location или применять динамическое ограничение с помощью переменных.

map $http_host $limit_rate {
    default 100k; # Устанавливаем ограничение по умолчанию
}

server {
    listen 443 ssl http2;

    location / {
        limit_rate $limit_rate; # Применяем ограничение скорости
    }
}

С переменной можно гибко управлять ограничением скорости.

Ограничение количества запросов для API с аутентификацией

Допустим, есть API, защищённый токенами, и нужно ограничить количество запросов для каждого пользователя.

http {
    limit_req_zone $http_authorization zone=api_limit:10m rate=10r/s;

    server {
        location /api/ {
            limit_req zone=api_limit burst=20 nodelay;
        }
    }
}

Используем заголовок Authorization в качестве ключа для идентификации пользователя.

Управление трафиком для стриминговых сервисов

Необходимо оптимизировать передачу больших файлов (видео, аудио) без потери качества.

Используем модуль slice:

location /video/ {
    slice 1m; # Разбиваем файл на куски по 1 МБ
    proxy_pass http://backend;
    proxy_set_header Range $slice_range;

    limit_rate_after 10m; # Ограничиваем скорость после 10 МБ
    limit_rate 1m;        # Ограничиваем скорость до 1 МБ/с
}

Разбивка на куски позволяет лучше использовать кэш и управлять передачей данных.

Ограничение на основе геолокации

Нужно установить разные ограничения скорости для пользователей из разных стран.

Настройка с использованием модуля geo:

geo $limit_rate {
    default         500k;    # Ограничение по умолчанию
    192.168.1.0/24  1m;      # Для определённой подсети увеличиваем лимит
    203.0.113.0/24  100k;    # Для другой подсети уменьшаем лимит
}

server {
    location / {
        limit_rate $limit_rate;
    }
}

Оптимизация и мониторинг

Включение статуса сервера

Позволяет получить информацию о текущем состоянии Nginx:

server {
    location /nginx_status {
        stub_status;
        allow 127.0.0.1; # Разрешаем доступ только с localhost
        deny all;
    }
}

Доступ к этой странице поможет мониторить активные соединения и обрабатывать данные в системах мониторинга.

Настройка логирования

Добавляем информацию о лимитировании в логи:

log_format custom '$remote_addr - $remote_user [$time_local] '
                  '"$request" $status $body_bytes_sent '
                  '"$http_referer" "$http_user_agent" '
                  '$limit_req_status';

access_log /var/log/nginx/access.log custom;

Поле $limit_req_status покажет статус ограничения PASSED, DELAYED, REJECTED.


Заключение

Настройка полноценного traffic shaping в Nginx — задача непростая, но крайне важная. Она требует внимания к деталям и понимания особенностей каждого случая.

Также, пользуясь случаем, напоминаю про открытый урок по основам балансировки нагрузки в Angie и Nginx, который пройдет сегодня (16 сентября) в 19:00.

На занятии познакомимся с архитектурой балансировки нагрузки в веб-приложениях, рассмотрим различные методы балансировки нагрузки в Nginx и Angie, различия в этих продуктах. А также поговорим об отказоустойчивости. Записаться на урок можно на странице курса «Администрирование Nginx/Angie».

Комментарии (0)