usepoint
menu

Протокол UDP: скорость вместо гарантий

Если TCP - это надежная заказная доставка с отслеживанием, то UDP - это быстрая открытка. Бросил в почтовый ящик и надеешься, что дойдет. Почему же тогда выбирают этот «ненадежный» протокол - об этом расскажем ниже

udp

Содержание:

Мы уже познакомились с TCP - протоколом, который устанавливает соединение, подтверждает доставку, переотправляет потерянные данные и сохраняет порядок байтов.

Теперь посмотрим на его «младшего брата» - UDP.

UDP - это протокол, который делает всё максимально просто и быстро, но отдаёт надёжность на совесть приложения.

Что такое UDP и чем он отличается от TCP

UDP (User Datagram Protocol) - протокол транспортного уровня, который отправляет отдельные короткие сообщения (датаграммы) без установления соединения, без подтверждений и без переотправок.

Снова напомним несколько терминов:

Транспортный уровень -  это уровень в модели TCP/IP, который работает поверх IP (сетевого уровня), добавляет порты и доставляет данные конкретному приложению на устройстве.

Порт - номер сервиса на конкретном IP-адресе (аналог номера квартиры в доме).

Пакет / датаграмма (в контексте UDP можно считать синонимами) - это порция данных, которую мы передаём за один раз. У неё есть IP-адрес отправителя и получателя, порт отправителя и получателя, полезные данные.

TCP строит поверх IP надёжный поток (как провод между программами).
UDP просто отправляет отдельные сообщения - «я это послал, а дальше будь что будет».

TCP сначала устанавливает соединение (3-way handshake), ведёт состояние: «что уже отправлено», «что подтверждено», «что нужно переотправить».

UDP не устанавливает соединение, не хранит внутри себя состояние общения, каждое сообщение самостоятельное: отправили - и забыли, что с ним дальше.

Отсутствие подтверждений и переотправки

В TCP есть механизм ACK (подтверждений) и таймаутов - получатель говорит: «я получил данные до такого-то номера», а если отправитель не видит подтверждения, он переотправляет сегмент.

В UDP ничего этого нет.

Как это выглядит на практике

  1. Приложение формирует сообщение (часто маленькое).
  2. Передаёт его в UDP вместе с IP-адресом получателя и портом получателя.
  3. UDP упаковывает это в датаграмму и отдаёт на IP-уровень.
  4. Дальше IP-пакет идёт по сети. При этом он может быть доставлен, но и может потеряться, прийти поздно или прийти задвоенным.

UDP сам по себе не проверяет дошли данные или нет, целые они или повреждённые, нужно ли что-то переотправить.

А что, если все же нужна надёжность?

Есть два пути:

  1. Берём TCP, если задачам подходит его модель: обычные веб-запросы, API,базы данных, файловые протоколы - почти всегда TCP.
  2. Строим надёжность в самом приложении поверх UDP, если нужен именно UDP. Тогда приложение само нумерует сообщения, отправляет свои подтверждения, хранит буферы и переотправляет данные при необходимости.

Так делают, например, некоторые протоколы для игр или передачи медиа, где нужен более гибкий контроль, чем даёт TCP.

Но ключевая мысль в том, UDP сам по себе ничего не гарантирует, кроме попытки отправить датаграмму. Всё остальное - забота приложений.

Задержка и потери

Несколько терминов, которые встанут на своё место именно с UDP:

Задержка (latency) - время от отправки пакета до его получения.

Переменная задержка (jitter) - когда задержка сильно плавает: например, один пакет пришёл через 30 мс, следующий через 80 мс, третий через 40 мс и т.д.

Потеря пакетов (packet loss) - часть пакетов просто не доходит.

В реальном времени (игры, голос, видео) небольшая задержка и потеря нескольких пакетов - терпимо, а большие задержки и сильный jitter - превращают голос в «робота», а стрим - в слайд-шоу.

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

Где оправдан UDP

Если UDP такой «ненадёжный», почему его вообще используют?
Потому что в ряде задач он даёт конкретные преимущества: меньше накладных расходов, ниже задержки и больше контроля у разработчика.

Разберём основные сценарии.

1) Медиастриминг (видео/аудио в реальном времени)

Примеры: онлайн-видеотрансляции, звонки по интернету, видеоконференции.

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

2) Real-time: игры, управление

Онлайн-игры (особенно шутеры и быстрые игры). Здесь игроки постоянно пересылают координаты, действия, события. Важны низкая задержка и быстрое обновление состояния. Потеря нескольких пакетов сделает движение рывками, но игра продолжит работать. 

Однако, задержка в полсекунды убивает ощущение управления и делает игру несправедливой. Поэтому многие игровые протоколы используют UDP, но  поверх него реализуют свою нумерацию пакетов и выбор, что обязательно должно дойти, а что можно пропустить.

3) IP-телефония (VoIP), голосовые чаты

Ситуация та же, что и с видео потеря нескольких миллисекунд звука = небольшое «похрустывание», а задержка в секунду = невозможность нормально разговаривать.

VoIP-протоколы (SIP+RTP и др.) обычно используют UDP,
чтобы минимизировать задержки и не тратить время на ожидание подтверждений.

4) DNS (система доменных имён)

DNS-запрос - это небольшой запрос «какой IP у такого-то домена?» и небольшой ответ «IP такой-то».

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

Поэтому многие DNS-запросы ходят по UDP (порт 53), а в сложных случаях/при больших ответах используется TCP, но это уже более детальная история.

5) Телеметрия, метрики, IoT-девайсы

Пример: датчик температуры каждые 5 секунд отправляет значение на сервер, а система мониторинга отправляет метрики нагрузки.

Особенности: данные отправляются регулярно, следующее значение всё равно скоро придёт, потеря 1–2 точек не критична.

В этом случае также проще использовать UDP, а не держать множество TCP-соединений, не тратя ресурсы на подтверждения.

Когда UDP - плохая идея

UDP не подходит, когда нельзя потерять данные.
Примеры: финансовые транзакции, платежи, заявки пользователей, изменения в базе.

Поэтому веб-сайты, REST API, интеграции между бизнес-системами, очереди сообщений почти всегда работают поверх TCP.