Акция Панель управления ispmanager для VDS — первый месяц бесплатно
до 31.07.2026 Подробнее
Выберите продукт

QUIC/UDP и HTTP/3 на Linux: sysctl, SO_REUSEPORT и pacing без мучений

HTTP/3 поверх QUIC — это UDP с другой динамикой: буферы, очереди, планирование отправки и прием. Разбираем рабочий профиль sysctl, зачем нужен SO_REUSEPORT, как включить fq‑pacing и UDP GSO/GRO, что проверить в ядре и сетевых драйверах, и как безопасно применить всё на проде с Nginx и HAProxy.
QUIC/UDP и HTTP/3 на Linux: sysctl, SO_REUSEPORT и pacing без мучений

HTTP/3 на QUIC кардинально меняет профиль нагрузки сервера: вместо TCP — UDP с пользовательским контролем перегрузки, меньшей толерантностью к джиттеру и повышенной чувствительностью к дропам в очередях. Поэтому «классические» тюнинги TCP почти не работают, а несколько ключевых параметров Linux дают львиную долю результата: буферы UDP, SO_REUSEPORT, планирование отправки (pacing) через sch_fq и поддержка UDP GSO/GRO. В этой статье собираю проверенный профиль и объясняю, зачем и когда применять каждую настройку. Для стабильной работы на многоядерных VDS эти принципы особенно важны.

Что особенного в QUIC/UDP по сравнению с TCP

QUIC использует UDP как транспорт, но реализует контроль перегрузки, восстановление потерь и мультиплексирование потоков в юзерспейсе. Это несет последствия:

  • Буферизация: переполнения приемных/передающих буферов UDP быстрее бьют по задержке и потерям, чем у TCP (нет ретрансмитов ядра).
  • Pacing: аккуратная шлифовка трафика на выходе критична — bursts легко перегружают NIC/qdisc/границу провайдера, растет loss и падает скорость HTTP/3.
  • Масштабирование: многопоточность через SO_REUSEPORT позволяет равномерно распределять потоки между воркерами/тредами и расшить CPU.
  • Offload: UDP GSO/GRO снижает накладные расходы на системные вызовы и обработку большого числа мелких дейтаграмм (актуально для initial и мелких stream‑фреймов).

Психология тюнинга меняется: вместо «разогреть TCP» мы предотвращаем локальные очереди и выравниваем отправку. Особенно чувствительны проложенные поверх туннелей и NAT‑траектории.

Минимальные требования к ядру и драйверам

Для комфортной работы HTTP/3 на проде рекомендую ядро 5.10+ (LTS): стабильная поддержка UDP GSO/GRO, зрелый sch_fq и драйверные багфиксы. На более старших ядрах часть возможностей будет недоступна или работать неполно.

  • UDP GSO: ускоряет отправку пачек UDP‑сегментов единым вызовом; полезно, если стек/библиотека QUIC умеет sendmmsg() с UDP_SEGMENT.
  • UDP GRO: агрегирует входящие дейтаграммы; экономит CPU, разгружает softirq.
  • sch_fq: планировщик, понимающий pacing по sk_pacing_rate и временным меткам; нужен для сглаживания bursts.

Быстрые проверки:

# Версия ядра
uname -r

# Возможности драйвера (признаки, зависят от NIC)
ethtool -k eth0 | egrep "gro|gso|udp|tx|rx"

# Активные qdisc
tc qdisc show dev eth0

Схема стека Linux: UDP/QUIC, хеширование SO_REUSEPORT и pacing через fq

Базовый профиль sysctl для QUIC/UDP

Цель — не «завинтить значения в потолок», а убрать локальные дропы и выровнять задержку. Стартовые значения ниже подходят для 1–10 Gbps интерфейсов и обычных VDS/VM. Настраивайте с учетом RAM и профиля нагрузки.

# /etc/sysctl.d/99-quic.conf

# Умеренные потолки сокетных буферов (байты)
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.rmem_default = 262144
net.core.wmem_default = 262144

# Нижние границы для UDP‑сокетов (байты)
net.ipv4.udp_rmem_min = 16384
net.ipv4.udp_wmem_min = 16384

# Очередь пакетов до обработки softirq (увеличить при всплесках PPS)
net.core.netdev_max_backlog = 16384

# Пейсинг по умолчанию через fq (важно для сглаживания bursts)
net.core.default_qdisc = fq

# Диапазон эфемерных портов (актуально для исходящих клиентских сокетов QUIC, например, при обратных прокси)
net.ipv4.ip_local_port_range = 10000 65535

# Опционально: более крупные опции сокетов
net.core.optmem_max = 262144

Пояснения:

  • rmem_max/wmem_max — потолок, не реальное потребление. Библиотеки QUIC (ngtcp2, quiche, lsquic и др.) могут масштабировать буферы через setsockopt() под нагрузкой.
  • udp_mem менять не советую: это тройка значений в страницах, легко «перекормить» систему. Если видите системные лимиты, сначала увеличьте rmem_max/wmem_max и пересмотрите количество активных потоков.
  • netdev_max_backlog уменьшит дропы при всплесках PPS, особенно на виртуальных интерфейсах; не путать с TCP backlog — у UDP нет очереди прослушивания.
  • default_qdisc=fq включает планировщик с поддержкой pacing; если по политике нужен AQMs типа fq_codel — оставьте его на WAN‑границе, а на сервере используйте fq для точного pacing.

Применяем без перезагрузки:

sysctl --system

SO_REUSEPORT: масштабирование приемника без боли

SO_REUSEPORT разрешает нескольким сокетам слушать один и тот же UDP‑порт. Ядро распределяет входящие дейтаграммы по хэшу 4‑кортежа (src/dst addr, src/dst port), обеспечивая липкость потока к конкретному воркеру. Это критично для QUIC: все пакеты конкретного соединения должны попадать к одному воркеру.

Плюсы:

  • Горизонтальное масштабирование: каждый воркер получает свою долю трафика и собственные буферы ядра.
  • Локальность кэша: меньше контеншена на локах и очередях.
  • Простая реализация: директива в конфиге Nginx/HAProxy или флаг при биндинге сокета.

Подводные камни и нюансы:

  • Балансировка завязана на 4‑кортеж; если вы балансируете на входе UDP‑потоки через внешний L4 (Anycast, UDP‑LB) с ребиндингом портов, убедитесь, что устройство сохраняет стабильность 4‑кортежа для каждого QUIC‑соединения.
  • Продвинутый вариант — eBPF‑программа SO_REUSEPORT, которая учитывает поля QUIC (например, DCID) для балансировки; это дает еще более равномерное распределение, но сложнее и требует аккуратного тестирования.

Pacing: сгладить всплески и снизить потери

Даже когда библиотека QUIC сама дозирует отправку, ядру полезно знать желаемый темп. sch_fq поддерживает pacing по sk_pacing_rate и временным меткам skb. Многие реализации QUIC выставляют SO_MAX_PACING_RATE и отправляют пачками через sendmmsg(). Результат — вместо резких bursts на выходе получаем ровный поток, у провайдера меньше микро‑дропов, выше реальная пропускная.

Минимум, что надо сделать на сервере:

  1. Включить fq как корневой qdisc.
  2. Проверить, что приложение/библиотека умеет pacing (большинство умеют по умолчанию).
  3. Убедиться, что NIC не насаживает лишних offload‑бурстов, конфликтующих с pacing.

Установка fq на интерфейс до перезагрузки:

tc qdisc replace dev eth0 root fq

Проверка статистики очереди и дропов:

tc -s qdisc show dev eth0

Если видите рост дропов на qdisc при пиках — это сигнал, что либо темп завышен, либо не хватает CPU, либо входящую волну нужно перераспределять (RPS/XPS) и/или поднимать net.core.netdev_max_backlog.

UDP GSO/GRO: меньше системных вызовов — больше полезной работы

QUIC оперирует множеством коротких дейтаграмм. UDP GSO (segmentation offload) позволяет приложению отправить крупный буфер с указанием размера сегмента, а ядро/NIC разобьет его на мелкие UDP‑пакеты. UDP GRO (receive offload) агрегирует обратную сторону на входе.

Проверка поддержки драйвером:

ethtool -k eth0 | egrep "udp|gro|gso"
# Примеры интересующих флагов (не у всех NIC)
# tx-udp-segmentation: on
# rx-udp-gro-forwarding: on
# generic-segmentation-offload: on
# generic-receive-offload: on

Включать/выключать offload нужно осознанно. Если драйвер/виртуальный NIC глючит на UDP GSO — лучше отключить соответствующий флаг, чем получать редкие, но болезненные потери и ретраи на уровне QUIC.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Nginx: HTTP/3, SO_REUSEPORT и GSO

Современный Nginx с поддержкой QUIC умеет слушать 443/udp и использовать reuseport. Важно включить правильный qdisc в системе и, при наличии, GSO в самом Nginx. Для работы HTTP/3 потребуется корректный TLS 1.3 и действующие SSL-сертификаты.

# Фрагмент nginx.conf (escape HTML)
worker_processes auto;

http {
    # Включаем GSO, если поддерживается ядром/драйвером
    quic_gso on;

    server {
        listen 443 quic reuseport;
        listen 443 ssl http2;
        # ... SSL/TLS 1.3 настройки ...
        # ... server_name, location и т.д. ...
    }
}

# Убедитесь, что на интерфейсе активен fq
# tc qdisc replace dev eth0 root fq

Пара моментов:

  • listen 443 quic reuseport; создаст отдельные UDP‑сокеты для воркеров и распределит потоки ядром.
  • quic_gso on; включает использование UDP_SEGMENT, если доступно. При проблемах с NIC/гипервизором временно отключайте.
  • Не забывайте про TLS 1.3 и корректные шифросuites; QUIC требует именно TLS 1.3.
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

HAProxy: QUIC‑листенеры и reuseport по тредам

Начиная с современных релизов HAProxy, QUIC доступен в продакшен‑качестве. Включайте многопоточность и reuseport на bind, чтобы ядро раздавало потоки по тредам равномерно.

global
    nbthread 4
    # ... прочие настройки ...

defaults
    mode http
    timeout client  30s
    timeout server  30s
    timeout connect 5s

frontend fe_https
    bind :443 ssl crt /etc/pki/tls/cert.pem alpn h3,h2,http/1.1 quic reuseport
    # ... ACL/маршруты ...
    default_backend be_app

backend be_app
    server s1 127.0.0.1:8080

Уточняйте синтаксис под вашу версию: в разных релизах опции quic/alpn/reuseport могли переезжать или меняться по умолчанию. Принцип неизменен: больше тредов + reuseport = лучше масштабирование на многоядерных VDS.

Наблюдаем: где теряются пакеты и где узкие места

UDP не прощает «тихие» переполнения. Несколько быстрых рецептов:

Примеры конфигов Nginx и HAProxy для HTTP/3/QUIC и reuseport

  • Ошибки сокетных буферов:
nstat -az | egrep "Udp(InErrors|RcvbufErrors|SndbufErrors)"
  • Очереди qdisc и дропы на выходе:
tc -s qdisc show dev eth0
  • Состояние UDP‑сокетов приложения (размеры буферов, флаги):
ss -u -einp | egrep ":443|udp"
  • Проверка фич NIC и счетчиков драйвера:
ethtool -k eth0 | egrep "gso|gro|udp"
ethtool -S eth0 | egrep -i "rx|tx|drop|fifo|udp"
  • Захват трафика для верификации рукопожатия и potenial reordering:
tcpdump -i any udp port 443 -vv -n

Интерпретация:

  • Растут UdpRcvbufErrors — поднимайте rmem_max/rmem_default и буферы приложения.
  • Растут дропы на fq — перепрофилируйте pacing, следите за CPU, увеличьте netdev_max_backlog, оцените RPS/XPS.
  • Много дропов на драйвере — проверьте offload‑флаги, IRQ affinity, NUMA и пересмотрите лимиты очередей.

Пошаговый план внедрения на проде

  1. Обновите ядро до 5.10+ и убедитесь в стабильности драйвера NIC на вашей платформе.
  2. Включите net.core.default_qdisc=fq, перезапустите сервисы сети или хост.
  3. Проверьте и примените sysctl из базового профиля, начав с безопасных значений для rmem_max/wmem_max.
  4. В приложении/веб‑сервере включите SO_REUSEPORT и несколько воркеров/тредов, привязывая их к CPU при необходимости.
  5. Проверьте поддержку UDP GSO/GRO и включите в приложении/сервере (например, quic_gso on в Nginx). При артефактах — откатите.
  6. Нагрузочное тестирование: сравните метрики UdpRcvbufErrors, дропов на fq, p95/p99 задержек и стабильность goodput на клиентах HTTP/3.
  7. Наблюдаемость в проде: дежурные дашборды по nstat, qdisc, ethtool‑счетчикам и basic SLO.

Частые антипаттерны

  • «Закрутить буферы до небес»: огромные rmem_max/wmem_max ведут к непредсказуемому росту RSS и увеличению задержки GC в приложении; лучше умеренные значения и правильный pacing.
  • Ставить fq_codel вместо fq на сервере для QUIC: AQM полезен на узком канале, но точный pacing дает fq.
  • Выключать GRO/GSO «на всякий случай»: если драйвер стабилен, эти фичи экономят CPU и дают ощутимый выигрыш.
  • Игнорировать SO_REUSEPORT при высокой PPS: один сокет на процесс — частые дропы на RCV path и горячие локи.
  • Не контролировать MTU: помните, QUIC специфицирует минимальный размер initial >= 1200 байт. Если под капотом есть туннели/VPN, реальная MTU меньше 1500 — тестируйте пейсинг и фрагментацию.

Финальные штрихи и советы

Три кита практического HTTP/3 на Linux: правильные буферы, SO_REUSEPORT и fq-pacing. UDP GSO/GRO — мощный бонус, если стек и драйверы здоровы. В проде это дает меньше «зубцов пилы» на goodput, более ровный p99 и отсутствие загадочных дропов при всплесках. Начните с малого профиля, включите наблюдаемость и масштабируйте по спросу.

Если готовите миграцию фронтов, посмотрите также про тонкую настройку кэша и подсказок сервера: диапазонные запросы и кэш в Nginx/Apache и HTTP 103 Early Hints. И обязательно документируйте, чем вызвано каждое изменение sysctl и qdisc — через полгода это сэкономит часы на форензику.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...