!Astro.props.image &&
← Назад к блогу

Задержка, пропускная способность и полоса пропускания: три числа, которые все путают

Удвоенная полоса часто ничего не меняет. Задержка, пропускная способность и полоса на одной аналогии, математика BDP и диагностика каждой из трёх.

Виктор Ведмич · 14 мин чтения

networking performance aws fundamentals

Приложение «тормозит», и приходит просьба: удвоить полосу пропускания (bandwidth).

Полосу удваивают. Ничего не меняется.

Так бывает часто, потому что за словом «тормозит» нередко стоит вовсе не нехватка ёмкости. Болтливый (chatty) сервис на каждое действие шлёт россыпь мелких запросов и за каждый платит полным круговым обходом. А где-то по дороге раздувается буфер, стоит трафику подрасти. Лишние мегабиты в секунду не убирают круговые обходы и не лечат раздутый буфер. Деньги уходят на расширение дороги, которая и так не была узким местом.

Путаница почти всегда растёт из одного: три разных числа сливают в одно расплывчатое понятие «скорость сети». Только скорость не описать одним числом. Чисел три, и каждое рассказывает свою историю:

  • Задержка (latency): время ожидания.
  • Пропускная способность (throughput): то, что реально доходит.
  • Полоса пропускания (bandwidth): потолок.

Дальше по тексту я держу английские термины в скобках: их многие знают именно как latency, throughput и bandwidth, и так проще сверяться с документацией и спид-тестами.

В русском путаница даже сильнее, чем в английском: и bandwidth, и throughput часто называют «пропускной способностью». Чтобы не запутаться, дальше потолок я зову полосой пропускания (bandwidth), а реальную доставку пропускной способностью (throughput). Перепутаешь эти три числа и будешь чинить не ту проблему. Вот все три на одном канале, в анимации. Смотри на путь одного пакета, на поток, который доходит, и на общий для них канал:

Одна аналогия на весь пост

Забудь на секунду про шоссе. Самая наглядная модель здесь: водопроводная труба.

  • Ширина трубы это полоса пропускания. Она задаёт максимум.
  • Вода, которая реально вытекает из дальнего конца за секунду, это пропускная способность.
  • Время, за которое первая капля проходит трубу насквозь, это задержка.

Держи эту картинку в голове. Каждое определение ниже сводится к ней, а где аналогия начинает хромать, скажу отдельно.

Задержка (Latency): сколько идёт один пакет

По-простому: сколько времени один пакет тратит на дорогу из точки A в точку B.

Точнее: односторонняя задержка это время, за которое пакет доходит до получателя. Обычно измеряют время кругового обхода (RTT, round-trip time): сколько занимает путь туда и обратно. И ping, и TCP измеряют RTT: для этого хватает часов на одной стороне. Чтобы измерить задержку в одну сторону, часы на обоих концах нужно синхронизировать. Не считай, что RTT равен удвоенной односторонней задержке. Прямой и обратный пути могут идти разными маршрутами, и даже на одном маршруте у каждого направления свои очереди (RFC 7679 называет обе причины). Как ни меряй, задержка складывается из четырёх частей: распространение сигнала (расстояние, делённое на скорость сигнала), передача, она же сериализация (выталкивание битов пакета в провод), обработка (роутер читает заголовок) и ожидание в очереди (пакет лежит в буфере).

Единица: миллисекунды (мс), иногда микросекунды.

Реальное число: между Нью-Йорком и Лондоном физический предел около 55 мс на круговой обход по оптике. Это теоретический минимум для прямого кабеля по дуге большого круга, около 5570 км в одну сторону. Между хорошо подключёнными серверами в этих городах RTT на практике около 70 мс: добавляются реальные трассы кабелей, маршрутизация и коммутация. С домашнего подключения выходит ещё больше. Но отрезвляет именно физика. Свет в оптоволокне идёт примерно 200 000 км/с (около двух третей скорости света в вакууме), так что реальные сети и так недалеко от этого предела. Скорость света новым оборудованием не увеличишь. Можно только сократить расстояние, ровно для этого и существуют CDN, или платить за него реже, сокращая число круговых обходов.

В аналогии с трубой: задержка в основном про длину трубы и скорость капли в ней. Здесь аналогия немного хромает. Ширина всё-таки влияет на две части из четырёх: широкая труба быстрее выталкивает каждый пакет в провод, и сериализация занимает меньше времени, а узкое место с запасом по ёмкости держит очередь короче. Распространению ширина безразлична, а на длинном маршруте именно оно обычно занимает большую часть задержки.

Пропускная способность (Throughput): сколько реально доходит

По-простому: сколько данных на самом деле проходит за секунду.

Точнее: объём данных, успешно доставленных за единицу времени, усреднённый за какой-то отрезок. Именно это число спид-тест показывает как «скорость загрузки».

Единица: биты в секунду, по нарастающей: Кбит/с → Мбит/с → Гбит/с.

Реальное число: канал «на 100 Мбит/с» при замере может выдавать 62 Мбит/с. Это нормально. Скорость снижают перегрузка сети, потери и повторные передачи пакетов, накладные расходы протокола, помехи в Wi-Fi и загруженный сервер на том конце.

В аналогии с трубой: пропускная способность это литры в секунду, которые реально вытекают из конца. Это не теоретический максимум, а результат замера в конкретных условиях: сколько канал пропускает прямо сейчас.

Полоса пропускания (Bandwidth): потолок

По-простому: самое большое, что канал в принципе способен унести.

Точнее: максимальная скорость передачи данных по каналу. Потолок, а не обещание. Для сквозного пути важен потолок самого узкого звена, то есть узкого места.

Единица: та же, что у пропускной способности. Биты в секунду: Мбит/с, Гбит/с.

Реальное число: те самые «100 Мбит/с» в тарифе. Платишь именно за это число. На реальной передаче видишь его редко, и описывает оно только канал доступа. Узким местом конкретной передачи с тем же успехом окажется Wi-Fi, перегруженный стык между сетями или сервер.

В аналогии с трубой: полоса пропускания это ширина трубы. Она ограничивает всё, но никогда не гарантирует, что труба полна.

Как три числа связаны

Вот соотношение, которое снимает большую часть путаницы:

Пропускная способность всегда меньше либо равна полосе пропускания. Никогда не больше.

Полоса это потолок (самого узкого звена); пропускная способность это то, что остаётся после того, как реальный мир возьмёт своё. Если канал заявлен на 100 Мбит/с, а замер показал 62 Мбит/с, числа друг другу не противоречат. Одно потолок, другое доставка.

И дальше то, что упускают чаще всего:

Задержка живёт на отдельной оси. Это время, а не объём.

Труба может быть очень широкой (большая полоса) и всё равно долго доставлять первую каплю (большая задержка). Даже у трансконтинентального канала с огромной ёмкостью остаётся задержка: сигналу нужно время, чтобы пройти это расстояние. Дополнительная полоса сокращает время передачи пакета в линию: для 1500 байт это 120 мкс на 100 Мбит/с и 12 мкс на 1 Гбит/с. Ожидание в очереди тоже может сократиться, а под нагрузкой именно оно нередко даёт основную задержку. Распространение она не сокращает никогда. Вот почему «просто добавь полосы» так часто ничего не меняет: если время уходит на расстояние и круговые обходы, расширение трубы их почти не трогает.

МетрикаНа какой вопрос отвечаетЕдиницаАналогия с трубой
Задержка (latency)Сколько идёт один пакет?мсВремя до первой капли
Пропускная способность (throughput)Сколько доходит за секунду?Мбит/сЛитры на выходе
Полоса пропускания (bandwidth)Каков максимум?Мбит/сШирина трубы

Маленькая ловушка единиц: биты против байтов

Скорости сети считают в битах в секунду (Мбит/с), а размеры файлов в байтах (МБ). В одном байте 8 бит, поэтому:

Канал на 100 Мбит/с упирается примерно в 12,5 МБ/с (100 ÷ 8), а самим данным файла достаётся чуть меньше: несколько процентов съедают заголовки пакетов.

Вот почему «быстрый» канал кажется медленным, когда смотришь на счётчик загрузки файла. Файлу в 1 ГБ по идеальному каналу 100 Мбит/с нужно не меньше 80 секунд, а не 8 (в десятичных единицах: 8000 мегабит ÷ 100 Мбит/с). Раздели Мбит/с на 8 и получишь МБ/с. Чтобы оценить время передачи, раздели размер файла на эту скорость.

Почему полоса большая, а скорость низкая: одна формула

Если нужен один кусок математики, который объясняет, почему канал на 1 Гбит/с может еле ползти, то это произведение полосы на задержку (BDP, bandwidth-delay product):

BDP (бит) = полоса (бит/с) × время кругового обхода (с)

BDP это объём данных, который должен быть «в полёте», то есть отправлен, но ещё не подтверждён, чтобы канал был занят весь круговой обход. Объём трубы, а не её ширина.

Вот почему это важно. TCP не замирает после каждой порции в ожидании ответа: окно у него скользящее, и каждое подтверждение (ACK) новых данных сдвигает его вперёд, так что отправитель передаёт дальше, пока позволяют окна приёма и перегрузки. Новые данные отправитель передаёт в пределах меньшего из двух окон (RFC 5681). Окно перегрузки (cwnd) это оценка отправителя, сколько выдержит сеть. Окно приёма (rwnd) объявляет получатель: столько данных он готов принять в буфер. Если меньшее из двух не дотягивает до BDP, это соединение не сможет полностью загрузить узкое место: часть каждого кругового обхода канал простаивает, как бы ни распределялись пакеты. Поэтому для одного соединения:

пропускная способность ≤ min(cwnd, rwnd) × 8 ÷ RTT    (окна в байтах, результат в бит/с)
пропускная способность ≤ полоса узкого места          (всегда)

Когда упираешься в окно, установившийся поток идёт близко к первой границе. Теперь подставим реальные числа. Чтобы заполнить канал 1 Гбит/с с RTT 100 мс:

BDP = 1 000 000 000 бит/с × 0,1 с = 100 000 000 бит = 12,5 МБ

Чтобы держать эту трубу полной, в полёте нужно 12,5 МБ. Но поле окна в заголовке TCP занимает 16 бит, так что без масштабирования окно приёма упирается в 65 535 байт, около 64 КБ. Если rwnd застрял на этом значении:

65 535 байт × 8 ÷ 0,1 с ≈ 5,2 Мбит/с

А теперь страшная тайна: одно соединение использует около 0,5% канала в 1 Гбит/с, и только из-за времени кругового обхода и маленького окна. Лечится масштабированием окна TCP (RFC 7323): с ним окно приёма может вырасти до 1 ГиБ. На современных системах оно включено по умолчанию, в Linux параметр net.ipv4.tcp_window_scaling по умолчанию равен 1.

И всё равно оно подводит, по трём причинам:

  • Множитель окна согласуется только в SYN, а RFC 7323 отмечает, что некоторые промежуточные устройства эту опцию вырезали.
  • Окно приёма не вырастет больше буфера приёма сокета. В Linux приложение, которое само выставляет SO_RCVBUF, отключает для этого сокета автонастройку буфера.
  • Большой rwnd снимает только одно ограничение. Окну перегрузки ещё нужно дорасти до BDP, на это уходят круговые обходы, а при перегрузке алгоритм может снова его урезать.

RFC 7323 называет такие маршруты «длинными толстыми сетями» (long, fat networks). На таких маршрутах рост RTT снижает потолок скорости соединения, если окно не меняется: чтобы заполнить канал, окно должно вмещать весь BDP, сколько полосы ни докупай.

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

Почему приложение тормозит, хотя с полосой всё в порядке

Когда что-то тормозит, не спеши докупать мегабиты. Сначала пройдись по реальным подозреваемым:

  1. Узкое место в задержке. Болтливый протокол платит за круговой обход на каждом запросе, который делает по очереди. Для большинства веб-страниц, собранных из множества мелких запросов, темп задаёт задержка, а не полоса, если канал уже достаточно быстрый. Правят бал расстояние и число обходов. Значит, лечение одно: платить за обходы реже. Группируй вызовы, переиспользуй соединения вместо повторных рукопожатий TCP и TLS, отправляй независимые запросы параллельно (HTTP/2 мультиплексирует их в одном соединении) или придвинь вызывающую сторону ближе к данным.

  2. Bufferbloat, раздувание буферов. Слишком большие буферы в роутерах и модемах забиваются под нагрузкой. В покое пинг, скажем, 20 мс, но стоит запустить загрузку, и он подскакивает до 200 мс и выше. Страдает всё интерактивное: видеозвонки, игры, SSH. Лечится это управлением очередью на узком месте, например алгоритмами CoDel или FQ-CoDel (RFC 8289, RFC 8290). Обычно их ставят вместе с шейпингом чуть ниже скорости канала, чтобы очередь собиралась там, где ею можно управлять. В OpenWrt это оформлено как SQM, умное управление очередью. BBR работает на другом уровне: это алгоритм управления перегрузкой на стороне отправителя. Он старается передавать быстро и не накапливать длинную очередь, но не гарантирует этого и остальным трафиком роутера не управляет. Быстрый канал разгребает тот же буфер быстрее, так что добавка полосы может уменьшить скачок. Но долгая загрузка всё равно накопит очередь, если отправитель передаёт быстрее, чем узкое место успевает пропускать.

  3. Пакеты в секунду, а не биты. В высоконагруженных системах реальный потолок часто задаёт частота пакетов, которую успевает обработать железо или виртуальная сетевая карта, а не сырая полоса. Разбор производительности сети на больших системах нередко показывает одно и то же: мелкие пакеты упираются в предел PPS задолго до того, как заполнится канал. В EC2 у каждого инстанса есть максимум PPS, который зависит от типа и размера. Драйвер ENA считает пакеты, задержанные в очереди или отброшенные сверх этого максимума, в счётчике pps_allowance_exceeded (он виден в выводе ethtool -S для ENA-интерфейса, часто это ens5, а не eth0). Для передачи больших объёмов джамбо-кадры (пакеты крупнее, числом меньше) снижают частоту пакетов, но только если больший MTU поддерживают оба конца и весь путь между ними. Инстансы EC2 текущего поколения поддерживают MTU 9001 байт, если его поддерживает весь путь внутри VPC. Через интернет-шлюз предел 1500 байт, а через AWS Site-to-Site VPN не больше 1446, а с некоторыми настройками шифрования и NAT Traversal ещё меньше. Прежде чем включать джамбо-кадры, проверь MTU всего пути. tracepath поможет, если до него доходят нужные ICMP-ответы, а для AWS Site-to-Site VPN ориентируйся на документированные значения MTU и MSS.

  4. Одно соединение, маленькое окно. Один поток TCP на длинном маршруте упирается в потолок далеко ниже скорости линии, пока его окно меньше BDP (см. математику выше). Параллельные соединения TCP могут поднять суммарную пропускную способность, потому что у каждого свои окна перегрузки и приёма. Поэтому документация Amazon S3 советует качать большие объекты параллельными запросами по диапазонам байтов. HTTP/2 этого не даёт. Все его стримы идут по одному соединению TCP и делят его окна: мультиплексирование экономит круговые обходы, но не окно. В EC2 есть ещё один предел на поток: при обычной сети один поток TCP или UDP между инстансами вне кластерной группы размещения ограничен 5 Гбит/с, какой бы ни была полоса инстанса. ENA Express поднимает предел до 25 Гбит/с между поддерживаемыми инстансами, но не выше общего лимита инстанса.

  5. Потери пакетов. Алгоритмы управления перегрузкой, которые ориентируются на потери (Reno, CUBIC), принимают потерю за перегрузку и урезают окно. Сильнее всех страдают длинные толстые сети: по словам RFC 7323, потери там могут действовать на пропускную способность «катастрофически». Даже 1–2% потерь способны обрушить один поток на канале с большим RTT. Сначала найди причину потерь. Дополнительная ёмкость может разгрузить перегруженный канал, но неисправную линию она не починит.

Заметь: за просьбой «добавьте полосы» часто скрываются задержки, потери или предел обработки пакетов.

Как на самом деле измерить каждое

Нельзя починить то, чего не видишь. У каждой метрики свой инструмент, и ни один из них не сводится к «посмотреть на Мбит/с в тарифе».

Для тестов пропускной способности и bufferbloat нужен свой сервер на другом конце. Подойдёт инстанс EC2 в нужном регионе. Запусти на нём iperf3 -s и открой в его группе безопасности TCP-порт 5201 (порт iperf3 по умолчанию) и ICMP echo для своего IP. В каждом клиентском терминале задай TEST_SERVER с адресом этого сервера:

# На своём сервере:
iperf3 -s                                # по умолчанию слушает TCP 5201

# Задержка: время кругового обхода и где по пути оно набегает
ping -c 20 "${TEST_SERVER:?set TEST_SERVER to your test server}"     # RTT каждого пакета, в мс
mtr -rwc 100 "${TEST_SERVER:?set TEST_SERVER to your test server}"   # RTT и потери по хопам, 100 циклов (около 100 с)
#  Потери на промежуточном хопе, которые не тянутся дальше по пути, часто означают,
#  что роутер ограничивает частоту ICMP-ответов. Разбирайся с потерями, которые доходят до цели.

# Пропускная способность: что маршрут реально доставляет
iperf3 -c "${TEST_SERVER:?set TEST_SERVER to your test server}" -t 30          # отдача (от клиента к серверу)
iperf3 -c "${TEST_SERVER:?set TEST_SERVER to your test server}" -R -t 30       # загрузка (от сервера к клиенту)
iperf3 -c "${TEST_SERVER:?set TEST_SERVER to your test server}" -R -P 4 -t 30  # 4 параллельных потока
#  Если 4 потока заметно обгоняют 1, что-то ограничивает одиночный поток:
#  окно, лимит на поток или одно ядро CPU.
#  Своего сервера нет? Спид-тест в браузере (Ookla / Cloudflare) меряет
#  пропускную способность до ближайшего сервера, а не по маршруту к нужному сервису.

# Полоса пропускания: ёмкость узкого места. Её меряют специальными методами,
#  а один замер скорости даёт только нижнюю границу, а не потолок.

# Bufferbloat: тест, который ловит тихого убийцу
# Терминал 1: держим пинг запущенным (останови его через Ctrl-C после теста)
ping "${TEST_SERVER:?set TEST_SERVER to your test server}"
# Терминал 2: забиваем канал в сторону загрузки на 30 секунд
iperf3 -c "${TEST_SERVER:?set TEST_SERVER to your test server}" -R -t 30
#  Смотри в терминал 1, пока идёт тест: RTT ровный = лишней задержки не видно,
#  RTT растёт и держится высоким = на узком месте копится очередь

Последний тест и есть самая полезная диагностическая привычка, какую только можно завести: пингуй во время загрузки. Если задержка держится ровно, этот тест не показал лишней задержки для ICMP. Убедись, что передача действительно загрузила узкое место, и проверь оба направления. Если она растёт, как только канал заполнился, и не падает, на узком месте копится очередь. Если добавить полосы, скачок может уменьшиться, а управление очередью на узком месте не даёт ей накапливаться. Вот это вживую. Запусти загрузку, смотри на линию, потом примени умную очередь:

Первый вопрос, который нужно задать

Когда приложение тормозит, первый вопрос никогда не «сколько у нас полосы».

Он такой: что из трёх на самом деле узкое место?

  • Если задержка, придвинь данные ближе или сократи число обходов.
  • Если RTT растёт под нагрузкой, сначала почини очередь на узком месте, а потом уже покупай ёмкость.
  • Если пропускная способность на длинном маршруте, смотри на окна (масштабирование, буферы, окно перегрузки), параллельные соединения и потери пакетов.
  • Если это правда полоса (узкое звено действительно забито), тогда, и только тогда, докупай.

Ошибёшься с диагнозом и окажешься там же, куда привела просьба из начала поста: заплатишь за расширение дороги, которая никогда не была проблемой.


Если было полезно: здесь я разбираю основы сетей, AWS и Kubernetes. Визуальная карусель к этому посту лежит у меня в LinkedIn.

Открыть поиск

Esc
↑ ↓ навигация ↵ открыть