TCP против UDP для разработчиков — Когда протокол действительно важен

Обновлено

Прекращайте рассматривать TCP и UDP как взаимозаменяемые флажки. Вот что на самом деле стоит вам за гарантию надежности, почему DNS работает через UDP, и почему ваша игра тормозит.

TCP против UDP для разработчиков — Когда протокол действительно важен 1
Реклама · УДАЛИТЬ?

Вы разрабатываете многопользовательскую игру. Игроки жалуются на задержки. Вы оптимизировали серверный код, сократили количество запросов к базе данных, и показатели задержки p99 выглядят нормально. Проблема проста: вы используете TCP. Это всё. Это и есть задержка.

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

Ставка, которую делает TCP

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

Это обещание стоит вам трёх вещей:

  • Задержка при установлении соединения — TCP требует трёхуровневого обмена перед передачей первого байта приложения. На сети с задержкой 50 мс вы тратите 150 мс до начала первого запроса.
  • Задержка головы потока — Это то, что убивает игры. Если пакет #5 потерян, TCP удерживает пакеты #6, #7 и #8 в буфере, ожидая, пока #5 будет повторно передан и придет. Поток блокируется. Позиция игрока из 100 мс назад сидит в буфере, пока сеть сама себя восстанавливает.
  • Перегрузка сети и избыточность — Алгоритм управления перегрузкой TCP (CUBIC, BBR и т. д.) снижает скорость передачи при обнаружении потерь. На потере данных это означает, что TCP снижает пропускную способность в момент, когда сеть испытывает трудности — именно в тот момент, когда пользователи это ощущают наиболее сильно.

То, что UDP на самом деле даёт вам

UDP отправляет датаграмму и не смотрит назад. Нет обмена, нет подтверждения, нет повторной передачи. Если пакет потерян, он исчезает. Получатель получает то, что пришло, в порядке, в котором оно пришло.

Это не ограничение — это и есть суть. Когда вам нужно меньше задержки, чем гарантия доставки, UDP позволяет вам делать этот выбор явно. Логика надёжности перемещается в прикладной слой, где вы можете принимать более умные решения о том, что действительно нужно повторно передавать.

В игре позиция игрока из 50 мс назад становится бесполезной — вам нужно текущее значение. С TCP вы бы буферизовали и ждали. С UDP вы отправляете последнее состояние и пропускаете всё устаревшее. Опыт становится плавнее даже при большем количестве потерь пакетов.

Сравнение TCP и UDP: то, что действительно важно

СвойствоTCPUDP
Установка соединенияТрёхуровневый обмен (добавляет 1,5× RTT до первого байта)Нет — отправляется сразу
Гарантия доставкиДа — повторная передача при потереНет — отправляется и забывается
Порядок пакетовОбеспечивается стекомВаша проблема
Задержка головы потокаДа — потеря одного пакета блокирует потокНет — каждый датаграмм является независимым
Управление перегрузкойВстроено (CUBIC, BBR и т. д.)Нет — реализуйте самостоятельно или пропустите
Общая задержка150–300 мс на холодных соединенияхПодмиллисекундная
Варианты использованияHTTP/1.1, HTTP/2, базы данных, передача файлов, электронная почтаDNS, игры, живой видео, HTTP/3 (QUIC)

Где каждый протокол действительно должен быть

DNS работает через UDP — и в этом есть урок

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

Если ответ слишком большой (DNSSEC записи, много A-записей), DNS переходит на TCP. Но в обычном случае — поисковый запрос по имени хоста — это чистый UDP, потому что выгодность этого обмена очевидна: трёхуровневый обмен будет длиться дольше, чем сам запрос.

Вы можете увидеть это поведение в действии с инструментом IO Tools DNS Lookup tool — введите домен и посмотрите, насколько быстро разрешаются отдельные типы записей. Эта скорость достигается за счёт того, что UDP устраняет полный круг обмена задержки.

Игры: UDP — единственный реальный ответ

Каждая основная библиотека сетевого взаимодействия в играх — Valve’s GameNetworkingSockets, Epic’s EOS transport, Unity’s UTP — построена на UDP. Причина — блокировка головы потока.

В соревновательной FPS вы отправляете обновления позиции каждые 64 такта — каждые 15 мс. Если один пакет потерян и TCP удерживает следующие пять, пока ожидает повторную передачу, вы вводите 75 мс задержки в самый неподходящий момент. С UDP вы немедленно отправляете следующее обновление. Клиент интерполирует между пропусками. Опыт становится плавным.

Большинство сетевых библиотек, построенных на UDP, реализуют собственную выборочную надёжность — номера последовательности, приоритетные очереди, выборочные подтверждения — но только для данных, которые действительно требуются: сообщения в чате, получение предметов, состояние матча. Позиционные данные не надёжны по дизайну. Устаревшее значение хуже, чем отсутствие значения.

Видео-трансляция: зависит от конкретного случая использования

Живые трансляции (Twitch, спортивные трансляции) используют протоколы на основе UDP — RTP, WebRTC, SRT — потому что несколько потерянных кадров допустимы, но задержка не должна быть. Вы не можете буферизировать 30 секунд трансляции, чтобы гарантировать плавность передачи.

Видеозаписи (Netflix, YouTube) на самом деле используют TCP, потому что буферизация скрывает стоимость. Несколько секунд предварительного буферизирования означают, что избыточность TCP не видна — вы просто видите плавную передачу. Штраф за задержку не важен, когда вы смотрите что-то, что произошло вчера.

HTTP/3 работает на UDP — и это меняет производительность веб-сайтов

HTTP/3 работает через QUIC, который работает на UDP. Google создал QUIC специально, чтобы исправить проблему блокировки головы потока TCP для трафика веб-сайтов. При использовании HTTP/2 через TCP один потерянный пакет блокирует все мультиплексированные потоки, использующие это соединение. QUIC реализует мультиплексирование потоков на уровне транспорта с независимыми подтверждениями — потеря одного пакета блокирует только один поток, а не все.

QUIC также интегрирует TLS в процесс установки соединения, что сокращает настройку холодного соединения до одного круга обмена (0-RTT при возобновлении сессии). На потере данных — мобильные соединения, перегруженные Wi-Fi — это является значимым улучшением. К 2024 году примерно 30% веб-сайтов поддерживают HTTP/3, и все основные браузеры включают его по умолчанию. Если вы развертываете за Cloudflare или современным CDN, вы, вероятно, уже предоставляете HTTP/3 без необходимости настройки.

Практическое дерево решений

Когда вы выбираете транспорт для нового протокола или сервиса, вопрос не «TCP или UDP?» — а «какие сбои я могу терпеть?»

  • Каждый байт должен прийти в правильном порядке, иначе операция завершается → TCP. Загрузка файлов, соединение с базой данных, API-запросы, электронная почта. Отсутствие данных означает повреждённые данные или ошибку парсинга.
  • Задержка важнее, чем гарантированная доставка → UDP. Игры, живое видео, голосовые звонки, телеметрия сенсоров. Устаревшее значение хуже, чем отсутствие значения.
  • Нужно оба, по сообщению → Работайте на UDP с выборочной надёжностью. QUIC делает это. Данные канала SCTP в WebRTC делают это. Библиотеки, такие как ENet и GameNetworkingSockets, делают это — хотя реализация самостоятельно является сложной работой, которая легко может быть выполнена с ошибками.

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

Заключение

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

UDP — правильный выбор, когда задержка является жёстким ограничением и ваша прикладная программа может управлять своей надёжностью. Это определённый набор проблем — реальные игры, живые медиа, специальные протоколы — а не общая оптимизация производительности, которую вы ищете, когда TCP кажется медленным.

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

Хотите убрать рекламу? Откажитесь от рекламы сегодня

Установите наши расширения

Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска

в Расширение Chrome в Расширение края в Расширение Firefox в Расширение Opera

Табло результатов прибыло!

Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!

Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?

новости с техническими моментами

Примите участие

Помогите нам продолжать предоставлять ценные бесплатные инструменты

Купи мне кофе
Реклама · УДАЛИТЬ?