8(800) 222 32 56
Панель управления
Решения для бизнеса

BBR и fq для LLM-стриминга: как убрать сетевую очередь из latency и не перепутать её с TTFT

BBR и fq для LLM-стриминга: как убрать сетевую очередь из latency и не перепутать её с TTFT
Подберите идеальное решение для ваших задач:
в России, США и Нидерландах обеспечат максимальную скорость. Воспользуйтесь всеми преимуществами надежного оборудования. Базовая помощь и техническое обслуживание входят в пакет услуг.
Стрим LLM может выглядеть «сетевым» даже тогда, когда сеть ни при чём: первый токен ждёт GPU, gateway держит буфер, а между токенами приложение само делает паузы. Из-за этого BBR часто включают слишком рано — получают другой congestion control, но не доказанное улучшение пользовательской latency. В этом runbook мы сначала разделим TTFT, межтокенные паузы и сетевую очередь, затем проверим BBR + fq на canary-узле и обязательно вернём baseline, чтобы подтвердить причинность. Цель не «ускорить Интернет одной sysctl», а понять, когда sender-side TCP pacing действительно влияет на LLM-стриминг.

Готовы перейти на современную серверную инфраструктуру?

В King Servers мы предлагаем серверы как на AMD EPYC, так и на Intel Xeon, с гибкими конфигурациями под любые задачи — от виртуализации и веб-хостинга до S3-хранилищ и кластеров хранения данных.

  • S3-совместимое хранилище для резервных копий
  • Панель управления, API, масштабируемость
  • Поддержку 24/7 и помощь в выборе конфигурации

Создайте аккаунт

Быстрая регистрация для доступа к инфраструктуре

Где на самом деле живёт задержка LLM-стрима

У LLM API слово latency слишком легко превращается в один общий график. Для диагностики этого недостаточно. Минимум разделите путь на три наблюдаемых интервала: время до первого байта/токена, паузы между последующими чанками и полную длительность ответа. Первый интервал часто определяется очередью запросов, prefill, доступностью GPU, cold start модели или работой gateway. Второй уже сильнее зависит от decode cadence, buffering и сетевой доставки. Третий смешивает всё сразу.

Практический пример: TTFT вырос с обычного уровня, а после первого токена поток идёт ровно. Это плохой кандидат для BBR: congestion control не сокращает очередь на GPU. Обратная картина — первый токен появляется вовремя, но далее клиент видит нерегулярные паузы, RTT под нагрузкой растёт, на sender-сокете видны retransmissions или очередь qdisc. Вот здесь сетевой слой уже заслуживает отдельного canary-теста.

Ещё одна типичная ловушка — настроить не тот хост. Если внешний TCP завершается на reverse proxy, ingress-controller или L7 gateway, именно он является sender для клиентского соединения. Изменение TCP congestion control на backend с vLLM не обязано повлиять на WAN-сегмент до пользователя. Для архитектуры gateway полезно сначала свериться с материалом про Private AI API, а для проблем на GPU — с разбором GPU throttling через DCGM и Prometheus.

Поэтому первый gate простой: вы должны назвать конкретный TCP sender, интерфейс, клиентский сегмент и пользовательскую метрику, которую собираетесь улучшить. Если этого нет, смена алгоритма — тюнинг вслепую.

Схема проверки сетевой причины задержек LLM-стриминга

Что BBR и fq действительно меняют в Linux

BBR — congestion control для TCP, который опирается на модель пропускной способности пути и RTT и управляет тем, сколько данных и с какой скоростью отправлять. В Linux алгоритм для новых соединений выбирается через net.ipv4.tcp_congestion_control; список уже зарегистрированных вариантов виден в net.ipv4.tcp_available_congestion_control. Документация ядра подчёркивает важную деталь: изменение sysctl задаёт алгоритм именно для новых TCP-соединений, поэтому проверять результат на старом keep-alive сокете бессмысленно.

fq — classless qdisc, рассчитанный прежде всего на локально генерируемый трафик. Он разделяет потоки и умеет уважать pacing, заданный TCP stack. Это не «ускоритель BBR», а scheduler на egress, который помогает выпускать пакеты во времени более управляемо. После перехода Linux на EDT TCP-level pacing больше не делает fq формально обязательным для работы BBR; Google отдельно отмечает, что на современных ядрах BBR может работать и с другими qdisc, хотя fq остаётся полезным на нагруженных серверах.

Отсюда главный operational вывод: тестировать нужно пару механизмов, а не магическую строку из старого блога. Сначала убедитесь, какой congestion control реально назначен сокету; затем — какой root qdisc реально висит на нужном интерфейсе. net.core.default_qdisc показывает дефолт для создаваемых qdisc, но фактическое состояние интерфейса смотрите через tc qdisc show.

Не путайте и версии BBR. Ветка Google BBRv3 существует отдельно от стандартного bbr, поставляемого конкретным дистрибутивным ядром. Нельзя по одному имени sysctl заключить, что у вас именно v3: это проверяется по происхождению и сборке ядра. Для production-runbook разумнее начинать с того BBR, который поддерживается вашим kernel/vendor profile, а экспериментальную ветку выносить в отдельный change.

Какой слой подозревать первым

TTFT растёт, GPU/очередь запросов насыщены, а после первого токена поток ровный — сначала ищите причину в inference path.
TTFT нормальный, но чанки приходят пачками — проверьте buffering, flush и место, где фактически завершается клиентский TCP.
Первый токен приходит вовремя, но под нагрузкой растут RTT, retransmissions или egress backlog — есть смысл ставить сетевой canary.
Схема пути LLM-стрима от TCP congestion control через fq и NIC к клиенту

Baseline начинается с identity: какой сокет, интерфейс и qdisc вы меняете

До любых изменений соберите evidence bundle. Нужны версия ядра, доступные congestion control, текущий алгоритм, реальный qdisc интерфейса, состояние NIC и несколько живых TCP-сокетов. Это защищает от самой неприятной ошибки: вы включили BBR на backend, а клиентский TCP на самом деле живёт в другом network namespace, на proxy или вообще в отдельном узле.

Сначала определите интерфейс по маршруту до тестового клиента: ip route get CLIENT_IP. Если сервис в контейнере, проверьте, где заканчивается TCP — в pod, host network, ingress или внешнем балансировщике. На bare metal и обычном VPS sender чаще очевиден, но и там source policy routing или bonding могут отправлять трафик не через тот интерфейс, который вы выбрали по имени.

bash
IFACE=ens5

uname -r
ip route get 203.0.113.10
sysctl net.ipv4.tcp_congestion_control
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.core.default_qdisc

tc qdisc show dev "$IFACE"
ip -s link show dev "$IFACE"
ss -tin state established | head -n 80
Снимок baseline перед сетевым canary

Адрес 203.0.113.10 здесь — документационный пример: замените его IP своего canary-клиента. Не копируйте имя ens5 вслепую. Сохраните вывод рядом с change ticket: после rollout и rollback вы будете сравнивать не память инженера, а одно и то же состояние.

Отдельно запишите topology class: физический dedicated, KVM/VPS, bonding, VLAN, NAT, внешний LB. BBR работает на TCP sender, но гипервизор, vSwitch, NIC ring, ToR и провайдерский uplink остаются другими очередями. Если проблема живёт там, красивый ss на гостевой ОС не доказывает, что вы контролируете bottleneck.

GPU-сервер, NIC и коммутатор при проверке сетевого тракта LLM-инференса

Сначала докажите сетевую причину, а уже потом меняйте congestion control

Хороший canary начинается с гипотезы, которую можно опровергнуть. Например: «при одинаковом запросе TTFT остаётся стабильным, но p95 паузы между SSE-чанками растут вместе с RTT/retransmissions на клиентском TCP». Это гораздо сильнее, чем «пользователь говорит, что ответ идёт рывками».

На application layer зафиксируйте TTFT, интервал между чанками и полную длительность ответа. На network layer — RTT, retransmissions, delivery/pacing rate конкретного сокета и статистику qdisc. На host layer — CPU softirq, NIC drops и saturation, если они есть в вашей телеметрии. Важен один и тот же запрос или фиксированный набор canary-запросов, одинаковая модель, одинаковый лимит токенов и один и тот же клиентский регион. Иначе вы сравните разные workloads.

Если ss -tin показывает app_limited, это сильный disqualifier для идеи «нам мешает congestion control»: sender не заполняет доступный путь постоянно. Для LLM это нормально — decode выдаёт токены дискретно. В такой ситуации BBR может быть технически активен, но пользовательский ритм определяет приложение. Аналогично, если retransmissions не меняются, qdisc backlog почти пуст, а паузы коррелируют с GPU decode, сетевой эксперимент лучше остановить.

Не забывайте прокси. Если Nginx/Envoy/HAProxy завершает клиентский TCP, снимайте socket evidence там. Backend-соединение между proxy и inference node может выглядеть идеально и никак не описывать WAN-очередь. Разницу между L4 и L7 особенно важно учитывать в streaming API: семантика buffering и timeout может дать те же симптомы, что и плохая сеть.

Готовы ли вы к сетевому canary

Снимите контрольный профиль CUBIC и не меняйте workload одновременно

Перед BBR нужен контрольный профиль текущего congestion control. На большинстве систем это будет CUBIC, но не предполагайте — прочитайте sysctl и фактический сокет. Ключевая дисциплина эксперимента: не менять одновременно модель, batching, max tokens, proxy buffering, kernel, MTU и congestion control. Один change — одна причинная гипотеза.

Для LLM streaming полезнее всего воспроизводить не гигантский download, а настоящий API-путь. Генератор трафика должен проходить через тот же TLS terminator и тот же network segment, что и пользователь. Сохраняйте timestamp первого байта и времена каждого чанка. Если ваш клиент умеет только «полное время запроса», вы не увидите разницу между TTFT и последующими паузами.

Сетевые counters снимайте в том же окне. ss -tin показывает RTT, congestion window, pacing rate и другие параметры TCP; для BBR там же могут появляться bandwidth/min_rtt state и признак app_limited. tc -s qdisc show нужен, чтобы видеть фактическую egress-очередь, а не только выбранный алгоритм TCP.

bash
IFACE=ens5

ss -tin state established | head -n 120
tc -s qdisc show dev "$IFACE"
nstat -az | grep -E 'TcpRetransSegs|IpOutDiscards'
ip -s link show dev "$IFACE"
Сетевые наблюдения во время контрольного прогона

Не задавайте заранее «нормальный процент улучшения». Такой порог без вашего traffic mix будет выдуманным benchmark. Сначала соберите распределение метрик на baseline, затем сравните canary в одинаковых условиях. Если разница меньше естественного разброса или исчезает после повторного прогона, честный вывод — причинность не доказана.

Для контекста по другим слоям полезно сопоставить этот эксперимент с NUMA-locality для GPU-инференса: там действует тот же принцип — низкоуровневый счётчик сам по себе не равен улучшению application SLO.

Включайте BBR и fq только на canary-узле

Когда baseline сохранён, переключайте один canary-host или небольшой canary-pool. Не начинайте с fleet-wide sysctl. Изменение congestion control затронет новые TCP-соединения, поэтому после переключения создайте новые клиентские сессии. Если приложение держит очень длинные keep-alive connections, старые сокеты могут продолжать жить с прежним профилем и смешивать результаты.

Сначала убедитесь, что модуль BBR доступен на вашем ядре. Затем переключите congestion control и qdisc. Команда tc qdisc replace ... root fq меняет root qdisc интерфейса прямо сейчас — это production change, а не безобидное чтение. Выполняйте его только на изолированном canary, где вы заранее знаете исходную конфигурацию и путь rollback.

bash
IFACE=ens5

sudo modprobe tcp_bbr
sysctl net.ipv4.tcp_available_congestion_control

sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
sudo tc qdisc replace dev "$IFACE" root fq

sysctl net.ipv4.tcp_congestion_control
tc -s qdisc show dev "$IFACE"
ss -tin state established | head -n 120
Canary-переключение BBR + fq

Не записывайте настройки в /etc/sysctl.d до окончания canary. Сначала докажите эффект и rollback. Persistence — отдельный change. Так проще избежать ситуации, когда временный эксперимент пережил reboot и внезапно стал новым baseline.

На виртуальной машине отдельно проверьте, что вы действительно контролируете нужный egress. Гостевой fq не заменяет очереди vSwitch или физического uplink. На выделенном сервере граница контроля шире: вы управляете kernel, qdisc, NIC и часто topology целиком, но провайдерская сеть и клиентский last mile всё равно остаются вне хоста.

Стоит ли продолжать BBR-canary

Сетевой тест на двух серверах

Как читать ss и qdisc без ложной победы по одной метрике

После переключения легко попасть в ловушку «в ss появился bbr — значит всё работает». Это доказывает только выбор congestion control для данного сокета. Для production-вывода нужны как минимум mechanism gate и application gate.

В mechanism gate смотрите, что новый сокет действительно использует BBR, что qdisc — fq, а pacing/delivery state выглядит правдоподобно. Сравните RTT, retransmissions и qdisc backlog с baseline. Если у BBR-сокета app_limited, не трактуйте низкий delivery rate как проблему сети: приложение само не подаёт достаточно данных. Для токенного стрима это частый режим.

В application gate проверяйте то, ради чего вообще делался change: распределение межтокенных пауз, tail latency стрима, число разрывов/повторных подключений и пользовательский SLO. TTFT держите рядом как контроль: если он внезапно изменился, вероятно, в эксперимент вмешалась очередь inference, autoscaling или другая нагрузка.

Сравнивать нужно идентичные traffic cohorts. Один быстрый клиент в соседнем дата-центре не доказывает эффект для мобильных пользователей через длинный WAN. И наоборот, один проблемный оператор связи не должен определять fleet-wide kernel policy. Разделите хотя бы внутренний/региональный и дальний внешний path.

Ещё один важный counterfactual — нагрузка. Повторите тест в спокойном окне. Если отличие BBR/fq проявляется только при заполненном egress и исчезает при низкой загрузке, это логично и полезно: вы локализовали queueing problem. Если «эффект» одинаков даже когда очередь пуста, ищите confounder.

Что считать доказательством

Новый сокет использует ожидаемый congestion control, root qdisc совпадает с планом, network counters меняются согласованно.
Меняется именно пользовательская метрика стрима: межчанковые паузы или tail latency, а не только внутренний TCP counter.
После возврата baseline эффект исчезает или ослабевает в том же workload. Без этого причинность остаётся гипотезой.
Высокоскоростной сетевой адаптер с равномерным TCP pacing

Rollback — это часть эксперимента, а не аварийная кнопка

Если canary выглядит лучше, следующий шаг — не rollout, а возврат к baseline. Это отрицательный контроль. Сначала верните исходный congestion control и qdisc, откройте новые TCP-соединения и повторите тот же canary-набор. Если streaming metric возвращается к прежнему распределению, причинная связь становится сильнее. Если улучшение остаётся, BBR мог просто совпасть по времени с другой переменной.

Исходный qdisc нельзя угадывать. Сохраните его до эксперимента и восстанавливайте из вашего IaC/change record. Ниже показан только пример с переменными; подставлять fq_codel или cubic автоматически нельзя, если это не ваш реальный baseline.

bash
IFACE=ens5
BASE_CC=cubic
BASE_QDISC=fq_codel

sudo sysctl -w net.ipv4.tcp_congestion_control="$BASE_CC"
sudo tc qdisc replace dev "$IFACE" root "$BASE_QDISC"

sysctl net.ipv4.tcp_congestion_control
tc -s qdisc show dev "$IFACE"
Пример явного rollback с заранее сохранёнными значениями

После rollback повторите mechanism gate и application gate в том же порядке. Если низкоуровневые TCP counters вернулись, а пользовательская метрика нет, значит bottleneck мигрировал или вы измеряете не тот слой. Например, сеть перестала быть ограничением, и теперь tail latency определяется gateway CPU, TLS, storage или decode cadence.

Именно поэтому rollback должен быть симметричным rollout. Не «вернули sysctl и разошлись», а заново проверили identity, сокет, qdisc и клиентский результат. Такой процесс длиннее, зато он предотвращает накопление мифических kernel tweaks, эффект которых никто не может воспроизвести.

Контрфакт перед rollout

Схема baseline, сетевого canary, rollback и повторной проверки

Когда BBR/fq не поможет — и может отвлечь от настоящей причины

Первый disqualifier — HTTP/3. Клиентский HTTP/3 работает поверх QUIC, а не TCP; Linux sysctl net.ipv4.tcp_congestion_control не управляет QUIC congestion control. У Google для QUIC BBR есть отдельная реализация в quiche. Если внешний API уже на HTTP/3, тюнинг TCP BBR на этом сегменте — просто не тот механизм. Сначала разберите транспорт; для этого пригодится статья про HTTP/3 для AI API.

Второй disqualifier — app_limited и низкая интенсивность данных. LLM token streaming часто не похож на bulk transfer: приложение выдаёт небольшие чанки с паузами между decode steps. Если bottleneck bandwidth не заполняется, congestion control имеет мало пространства для улучшения пользовательского ритма.

Третий — buffering выше TCP. L7 proxy может копить данные до размера/таймера, библиотека — не flush-ить каждый chunk, а клиент — сам буферизовать UI. Тогда сеть доставляет всё корректно, но пользователь видит «пачки». Смотрите место фактической задержки, а не только wire metrics.

Четвёртый — saturation на GPU или admission control. Если очередь запросов растёт, TTFT уезжает, а inter-token gap ухудшается из-за конкуренции за compute, BBR здесь не лекарство. Иногда именно ограничение дорогих запросов через quota/rate policy стабилизирует сервис лучше сетевого тюнинга; см. разбор rate limits и quotas для дорогих API.

Пятый — bottleneck за пределами вашего host. Wi‑Fi пользователя, мобильная сеть, межоператорский peering и provider uplink могут доминировать. BBR на sender способен изменить своё поведение, но не даёт вам контроль над чужой очередью. Поэтому коммерчески ценен не сам алгоритм, а возможность воспроизводимо управлять своей частью пути и честно отделять её от внешней.

BBR/fq вообще относится к вашему случаю?

Production rollout: ценность не в sysctl, а в контроле сетевого пути

Если canary прошёл mechanism gate, application gate и rollback-контрфакт, можно обсуждать rollout. Делайте его по topology class: одинаковые kernel build, NIC/driver, qdisc baseline, MTU и роль в трафике. Не смешивайте в один wave разные типы виртуализации и физические серверы — одинаковый sysctl поверх разных egress paths не создаёт одинаковую систему.

Persistence включайте отдельным шагом. Зафиксируйте sysctl в управляемой конфигурации, qdisc — в network bootstrap/systemd unit или другом IaC-механизме, который ваша команда умеет проверять и откатывать. После reboot должен существовать тот же evidence gate: congestion control доступен, новые сокеты его используют, qdisc соответствует профилю, application canary проходит.

Для выделенной инфраструктуры это и есть естественный offer bridge. Dedicated host даёт ownership над kernel profile, qdisc, NIC, IRQ/CPU placement, reboot window и rollback. Это не обещание, что «dedicated + BBR всегда быстрее». Наоборот: ценность в том, что один и тот же baseline можно воспроизвести, а изменение — изолировать. Если команда не контролирует host networking или провайдер запрещает нужные kernel/qdisc changes, эксперимент может быть организационно невозможен.

При этом сеть не существует отдельно от inference topology. Если после устранения egress queue bottleneck переезжает в CPU/memory locality, вернитесь к системной диагностике. В multi-GPU сценариях полезно сопоставить сетевой rollout с NUMA-locality и другими host-level gates, а не пытаться одним TCP tweak закрыть всю цепочку.

Какой rollout соответствует уровню контроля

Максимальный host-level control: kernel, qdisc, NIC и reboot profile можно сделать частью воспроизводимого baseline.
Гостевая ОС управляет своим TCP/qdisc, но vSwitch и физический uplink остаются внешними очередями; проверяйте границы влияния.
Если внешний gateway держит клиентский TCP, kernel tuning backend не заменяет настройки и наблюдаемость самого gateway.
Серверный сетевой тракт

Чек-лист перед rollout и главный вывод

BBR + fq имеет смысл не тогда, когда «так советуют для VPS», а когда вы доказали sender-side queueing problem на реальном LLM streaming path. Перед production change проверьте: известен фактический TCP sender; TTFT отделён от межтокенных пауз; baseline CUBIC/текущего CC сохранён; root qdisc известен; на canary открываются новые соединения; mechanism и application metrics улучшаются согласованно; rollback возвращает картину к baseline; после изменения bottleneck не переехал в GPU, gateway или другой сетевой слой.

Если хотя бы один из этих пунктов не выполняется, результат лучше назвать «интересным наблюдением», а не оптимизацией. Такой консерватизм экономит время: kernel tuning, который нельзя причинно связать с SLO, быстро превращается в технический долг.

Источники для перепроверки механики — актуальная документация Linux IP sysctl, описание tc-fq и материалы Google BBR. Они важнее старых рецептов с одной строкой sysctl.conf, потому что поведение pacing и kernel networking менялось.

Начните с одного canary-host и одного фиксированного набора streaming-запросов. Если эффект выдерживает повтор, rollback и reboot — тогда у вас есть инженерное основание для rollout. Если нет, это тоже хороший результат: вы исключили один слой и можете идти дальше по цепочке без гадания.

Nftables sets: динамические списки IP без сотен правил
Решения для бизнеса

Nftables sets: динамические списки IP без сотен правил

Практическое руководство по nftables sets: именованные и временные наборы, диапазоны, составные ключи, атомарные обновления, автоматизация и безопасный rollback.

Как повысить антиплагиат: 8 эффективных способов 2021 года
Сайт

Как повысить антиплагиат: 8 эффективных способов 2021 года

Чем популярнее тема, тем сложнее написать уникальный текст. Большинство письменных трудов должно содержать цитаты, термины,

Медиасервер: зачем он вам нужен и как его настроить?
Решения для бизнеса

Медиасервер: зачем он вам нужен и как его настроить?

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