Гигабитный канал кончается на 40 мегабитах: где теряется всё остальное
В договоре и в панели написано «канал 1 Гбит/с», а scp до сервера в другой стране упорно показывает 30-40 Мбит/с, и это не обман провайдера. Гигабит — это пропускная способность порта, а не гарантия того, что одно ваше соединение эту полосу выберет. Разберёмся, куда девается заявленная скорость и что с этим реально можно сделать, а не просто «попробуйте другой провайдер».
Содержание
- Заявленная скорость — это пропускная способность порта, а не ваша
- Bandwidth-delay product: почему одно соединение не выбирает всю трубу
- Задержка и потери пакетов — второй удар по скорости одного потока
- MTU, фрагментация и переоценённые «широкие» каналы
- Как измерить реальную пропускную способность: iperf3
- Что можно реально сделать: параллельные потоки и тюнинг TCP-стека
Заявленная скорость — это пропускная способность порта, а не ваша
Когда в тарифе написано «1 Гбит/с», это характеристика физического порта на коммутаторе и аплинка сервера — сколько бит в секунду в принципе может протолкнуть через себя эта труба. Это не обещание, что конкретно ваше TCP-соединение до конкретного получателя выберет всю эту полосу. Труба может быть широкой, а узкое место — не в ней, а в том, как её использует протокол передачи.
Первый источник потерь — оверхед самих протоколов, и он есть всегда, даже на идеальном канале без задержек и потерь. Каждый байт полезной нагрузки едет внутри нескольких вложенных заголовков:
- Ethernet-кадр добавляет заголовок и межкадровый интервал — на каждый пакет уходит порядка 38 байт служебных данных сверх полезной нагрузки.
- IP-заголовок — минимум 20 байт для IPv4, у IPv6 — 40 байт.
- TCP-заголовок — минимум 20 байт, больше с опциями (timestamps, SACK, window scaling).
- Если канал зашифрован (VPN, TLS) — добавляются заголовки туннеля и шифрования, иногда с фрагментацией сверху.
На пакетах в 1500 байт (обычный Ethernet MTU) оверхед — это единицы процентов, терпимо. Но реальный трафик редко состоит из пакетов максимального размера: мелкие HTTP-запросы, ACK-пакеты, интерактивный трафик — там на служебные заголовки уходит куда большая доля каждого пакета. Плюс сам TCP тратит часть полосы на ACK-трафик в обратную сторону — на асимметричных каналах (например, спутник или некоторые мобильные сети) это заметно режет эффективную скорость.
Итог: даже без единой потери пакета и без задержки вы никогда не получите ровно 1000 Мбит/с полезных данных — только близко к этому, обычно 92-97% от номинала на крупных пакетах. Это фон. Настоящие потери начинаются дальше — на задержке, окне и потерях пакетов.
Bandwidth-delay product: почему одно соединение не выбирает всю трубу
Вот здесь теряется больше всего, и именно это чаще всего путают с «плохим каналом». TCP — протокол с подтверждением: отправитель не может выслать данных больше, чем помещается в окно — объём данных, отправленных, но ещё не подтверждённых получателем. Пока не пришёл ACK на уже отправленное, окно не «сдвигается», и слать больше нельзя.
Чтобы полностью занять канал с заданной полосой, нужно держать в полёте ровно столько данных, сколько канал успевает пропустить за время оборота одного пакета туда-обратно. Это и есть bandwidth-delay product (BDP):
BDP (байт) = Пропускная способность (байт/с) × RTT (с)
Пример для ориентира (реальные цифры на вашем маршруте будут другими — это только чтобы показать порядок величины). Канал 1 Гбит/с — это 125 МБ/с. Если RTT до сервера — 100 мс (условно, для маршрута через океан это реалистичный порядок), то:
BDP = 125 000 000 байт/с × 0,1 с = 12 500 000 байт ≈ 12 МБ
Чтобы одно TCP-соединение выбрало весь гигабит на этом RTT, окно должно вмещать порядка 12 МБ данных «в полёте» одновременно. А классическое TCP-окно без масштабирования (window scaling) ограничено 65 535 байтами — это в 190 раз меньше нужного. Без масштабирования на таком RTT одно соединение физически не может выдать больше нескольких мегабит в секунду, сколько бы ни было полосы в канале.
Window scaling (RFC 1323) решает это математически — окно может масштабироваться до гигабайт, — но реальный потолок задаёт не только он: ещё размер буферов приёма и отправки на обеих сторонах (net.core.rmem_max, net.ipv4.tcp_rmem и симметричные wmem-параметры), и они должны быть достаточно большими, чтобы вместить BDP. Если буфер меньше расчётного BDP — окно физически не сможет вырасти до нужного размера, и канал снова недоиспользуется, даже если window scaling включён.
Отсюда практическое правило: чем больше произведение полосы на задержку, тем сильнее одно-единственное TCP-соединение проигрывает нескольким параллельным. Подробный разбор формулы, window scaling и настройки sysctl для конкретно этого случая — в статье про TCP-окно и канал через океан.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверЗадержка и потери пакетов — второй удар по скорости одного потока
RTT сам по себе не «съедает» полосу — он определяет, насколько большим должно быть окно (см. BDP выше). А вот потери пакетов бьют по-другому и сильнее, чем кажется на глаз.
Когда пакет теряется, TCP интерпретирует это как сигнал перегрузки сети и снижает скорость отправки — размер окна перегрузки (congestion window, cwnd) резко падает, а затем медленно восстанавливается (сколько именно — зависит от алгоритма управления перегрузкой: Reno, CUBIC, BBR ведут себя по-разному). На канале без потерь окно растёт, пока не упрётся в лимит буфера или полосы. На канале с регулярными потерями окно постоянно «подрезают» раньше, чем оно успевает разогнаться до максимума — соединение живёт рывками, а не на полной скорости.
Хуже то, что эффект потерь усиливается вместе с RTT. На коротком RTT (пинг до соседнего дата-центра) TCP успевает быстро восстановиться после потери и снова разогнаться. На длинном RTT (трансатлантический или трансконтинентальный маршрут) тот же самый процент потерь обходится куда дороже — окну требуется больше времени на восстановление до прежнего размера, и на это время эффективная скорость проседает. Именно поэтому один и тот же провайдер с одинаковым паттерном потерь на разных плечах маршрута может давать совершенно разную реальную скорость — не потому что канал разный, а потому что задержка разная.
Отдельная проблема — потери, которые почти не видны в обычном ping: ICMP по многим маршрутам приоритизируется иначе, чем TCP-трафик, и может идти чисто, пока реальные data-пакеты проседают под нагрузкой. Если подозреваете именно потери, а не проблему с окном, стоит смотреть не на пинг, а на счётчики retransmit конкретно TCP-сессии — например, через ss -ti во время передачи.
MTU, фрагментация и переоценённые «широкие» каналы
MTU (Maximum Transmission Unit) — максимальный размер пакета, который проходит по сети без фрагментации. Стандарт для Ethernet — 1500 байт. Если где-то на маршруте пакет оказывается больше MTU этого участка, он либо фрагментируется на несколько частей (дополнительный оверхед и точка отказа), либо, если стоит флаг «не фрагментировать» (DF), отбрасывается с ICMP-сообщением о необходимости уменьшить размер (Path MTU Discovery). Если это ICMP-сообщение теряется где-то по дороге (типичная ситуация за файрволами, которые режут ICMP целиком) — соединение просто зависает на определённых размерах пакетов, а мелкие проходят нормально. Симптом узнаваем: сайт открывается, ssh работает, а именно передача файла или загрузка тяжёлой страницы обрывается или виснет.
VPN и туннели усугубляют проблему: у зашифрованного трафика заголовки инкапсуляции съедают часть MTU, и если внутренний интерфейс продолжает считать, что можно слать пакеты по 1500 байт, каждый из них будет либо фрагментироваться, либо теряться при DF. На практике внутри туннеля MTU обычно приходится снижать на несколько десятков-сотню байт — конкретное значение зависит от протокола туннелирования и стека шифрования.
Второй, менее очевидный эффект MTU — на пропускную способность даже без явных обрывов. Каждый пакет, вне зависимости от размера, несёт фиксированный оверхед заголовков (см. первый раздел) и требует отдельной обработки — прерывания на сетевой карте, обработки в стеке ядра. При том же объёме данных мелкие пакеты означают больше пакетов в секунду, а значит больше накладных расходов на пакет и выше нагрузка на CPU при той же полосе. Это одна из причин, почему на десятигигабитных и более быстрых интерфейсах имеет смысл включать jumbo frames (MTU 9000) там, где это поддерживает вся сеть на всём пути — меньше пакетов на тот же объём данных, меньше накладных расходов. На обычном интернет-канале с непредсказуемым маршрутом трогать MTU в бо́льшую сторону обычно бессмысленно и рискованно — договориться об этом со всеми промежуточными узлами вы не можете. Подробный разбор фрагментации и типичных симптомов — в статье про MTU и загадочные обрывы.
Как измерить реальную пропускную способность: iperf3
Прежде чем что-то тюнить, нужно понять, где именно теряется скорость — а для этого не годятся браузерные спидтесты: они одновременно тестируют TLS-хендшейк, чужой сервер и загрузку CDN, смешивая слишком много переменных. iperf3 меряет именно то, что нужно: сколько байт реально проходит между двумя точками, с контролем числа потоков и протокола.
Базовый тест — сначала поднимаете сервер на одной стороне:
iperf3 -s
И запускаете клиент на другой:
iperf3 -c ip.adres.servera -t 30
Это тест одним TCP-потоком за 30 секунд. Если результат сильно ниже заявленной полосы канала — велика вероятность, что дело именно в BDP и окне, а не в реальном ограничении сети. Проверить гипотезу просто — запустить тот же тест в несколько параллельных потоков:
iperf3 -c ip.adres.servera -t 30 -P 8
Флаг -P 8 поднимает 8 параллельных TCP-соединений одновременно. Если суммарная скорость восьми потоков заметно выше, чем у одного, — это прямое подтверждение, что канал шире, а упирались вы именно в окно одного соединения на данном RTT, а не в физический потолок сети.
Полезные дополнительные флаги:
-R— реверс-тест (сервер отправляет клиенту), проверяет асимметрию канала в обе стороны.-u -b 1000M— тест по UDP с заданной полосой, показывает потери пакетов напрямую (в TCP они маскируются повторными передачами).-i 1— интервал вывода промежуточных результатов раз в секунду, полезно видеть просадки во времени, а не только итоговую цифру.
Пока тест идёт, полезно параллельно смотреть на состояние TCP-сессии через ss -ti — там видны cwnd (окно перегрузки), rtt и счётчик retrans (повторных передач). Растущий retrans во время теста — прямой признак потерь пакетов на маршруте, а не проблемы с настройками окна. Подробную методику измерений, интерпретацию результатов и типичные ошибки разбирали отдельно — в статье про измерение скорости через iperf3.
Что можно реально сделать: параллельные потоки и тюнинг TCP-стека
Когда причина ясна (а после тестов из предыдущего раздела она обычно ясна), доступны два рабочих направления — и они не взаимоисключающие, обычно нужны оба.
Параллельные потоки на уровне приложения. Если тестами подтвердилось, что канал шире, чем выбирает один поток, — самое практичное решение часто не в ядре, а в приложении. Для передачи файлов вместо scp (одно соединение) стоит попробовать rsync с несколькими параллельными процессами по частям файла, axel или aria2c для скачивания в несколько потоков, rclone с флагом --transfers для синхронизации с облачными хранилищами. Для HTTP-трафика этим же занимается сама природа протокола — браузер и так открывает несколько соединений параллельно (а HTTP/2 и HTTP/3 добавляют мультиплексирование поверх одного или нескольких соединений).
Тюнинг TCP-стека на сервере. Если приложение ограничено одним соединением (это частый случай для стриминга и части баз данных), тюнят стек:
# Включить window scaling (обычно уже включено по умолчанию в современных ядрах)
sysctl -w net.ipv4.tcp_window_scaling=1
# Увеличить максимальные буферы приёма и отправки под расчётный BDP
sysctl -w net.core.rmem_max=134217728
sysctl -w net.core.wmem_max=134217728
sysctl -w net.ipv4.tcp_rmem="4096 87380 134217728"
sysctl -w net.ipv4.tcp_wmem="4096 65536 134217728"
# Алгоритм управления перегрузкой — BBR обычно лучше держит скорость
# на маршрутах с потерями и большим RTT, чем классический CUBIC
sysctl -w net.ipv4.tcp_congestion_control=bbr
Значения буферов подбирайте под реальный BDP вашего маршрута (см. формулу выше), а не копируйте числа вслепую — с запасом, но без фанатизма: слишком большие буферы на нестабильном канале с потерями могут увеличивать задержку (bufferbloat) вместо того, чтобы помогать. Изменения через sysctl -w действуют до перезагрузки — для постоянного эффекта добавляйте их в /etc/sysctl.d/99-tcp-tuning.conf и применяйте sysctl --system.
Отдельно проверьте, не упираетесь ли вы в характеристики самого порта: если вопрос стоит «хватит ли гигабита» или «нужен ли 10G» — это уже не вопрос тюнинга, а вопрос выбора тарифа, разобранный в статье про выбор между 1G и 10G каналом.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Как быстро понять, в чём причина — в окне, в потерях или в реальном ограничении канала?
Запустите iperf3 одним потоком, затем с -P 8. Если суммарная скорость параллельных потоков заметно выше одиночного — дело в окне/BDP. Если оба теста упираются в одинаковый низкий потолок — либо реальный лимит канала (тариф, шейпинг у провайдера), либо потери пакетов, которые видны через retrans в ss -ti или через UDP-тест iperf3 -u.
Увеличение буферов TCP всегда безопасно?
Нет. На стабильном канале с большим RTT — да, помогает. На нестабильном канале с потерями слишком большие буферы могут увеличивать задержку под нагрузкой (bufferbloat) — очередь пакетов растёт, но не разгружается, а latency ползёт вверх. Подбирайте буферы под расчётный BDP, а не «побольше на всякий случай».
BBR всегда лучше CUBIC?
Не всегда — но на маршрутах с заметным RTT и случайными потерями (не связанными с реальной перегрузкой) BBR обычно держит скорость стабильнее, потому что не так агрессивно интерпретирует единичную потерю как сигнал перегрузки. На коротких low-latency маршрутах внутри одного дата-центра разница обычно малозаметна. Меняя алгоритм на проде, проверяйте эффект тестами до и после, а не по одной рекомендации из статьи.
Нужно ли поднимать MTU до 9000 (jumbo frames), чтобы получить больше скорости?
Только если это поддерживает вся сеть на всём пути между вами и получателем, включая коммутаторы провайдера. На обычном интернет-канале с непредсказуемым маршрутом это обычно не контролируется вами и может привести к обрывам вместо ускорения. Jumbo frames имеет смысл в контролируемой сети — например, между серверами внутри одного дата-центра на 10G+ интерфейсах.
Почему при копировании файла через VPN скорость ещё ниже, чем напрямую?
К base-эффектам (окно, RTT, потери) добавляется оверхед шифрования и инкапсуляции самого туннеля, а также обычно уменьшенный эффективный MTU внутри туннеля — см. раздел про MTU выше. Плюс однопоточные VPN-протоколы часто ограничены одним TCP- или UDP-потоком по конструкции, так что параллелизация на уровне приложения тут не всегда доступна.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →