Расшифровка четырех RFC третьего транспортного протокола — задача, сравнимая с притчей о слепом человеке, пытающемся понять слона. Автор делится деталями QUIC. — theregister.com
Пока Ларри готовил большую часть контента для главы «Запрос/Ответ» для следующего издания нашей книги, я взял на себя руководство по написанию раздела о QUIC (Quick UDP Internet Connections), поскольку я внимательно следил за его разработкой.
Мы ожидаем, что в ближайшие годы роль QUIC будет столь же важна, как и роль TCP, что означает, что он заслуживает более детального освещения, чем то, которое мы предоставили в последнем издании. Поэтому я углубился в биты и байты QUIC глубже, чем делал это раньше, с целью довести освещение до уровня нашего освещения TCP. Помимо изучения RFC, я нашел много полезной информации в исходной спецификации дизайна QUIC, а также в некоторых конференционных публикациях о дизайне и оценке SPDY (предшественника HTTP/2) и QUIC.
Одна довольно тривиальная вещь, которая затрудняет мне освоение QUIC, — это тот факт, что в его RFC (четыре документа общим объемом в сотни страниц) отсутствуют схемы заголовков пакетов. Я полагаю, что причина этого в том, что QUIC широко использует поля переменной длины, которые часто не выровнены по 32-битным границам, что делает схемы заголовков пакетов несколько сложными и менее аккуратными. Я решил попробовать нарисовать свои собственные — вот один пример, который я привожу здесь в надежде услышать от других, считают ли они его полезным или запутанным.
Структура заголовков пакетов в QUIC
Для сравнения, RFC 9000 представляет этот заголовок следующим образом:
Long Header Packet {
Header Form (1) = 1,
Fixed Bit (1) = 1,
Long Packet Type (2), Type-Specific Bits (4),
Version (32),
Destination Connection ID Length (8),
Destination Connection ID Length (8),
Destination Connection ID (0..160),
Source Connection ID Length (8),
Source Connection ID (0..160), Type-Specific Payload (..),
}
Возможно, я просто старомоден в том, что люблю видеть заголовки пакетов, когда изучаю новый протокол. И я признаю, что текстовая версия содержит больше информации; например, она подробно описывает флаги. Не стесняйтесь сообщить нам о ваших предпочтениях. (Полагаю, мы уже знаем, что думает рецензент с «Стеной текста»!)
Использование полей переменной длины пронизывает весь протокол, в попытке сбалансировать эффективность и перспективность.
И TCP, и IP имеют историю определения 32-битных полей, которых оказалось недостаточно; QUIC в целом избегает этой проблемы, позволяя полям быть очень большими, например, 160-битным идентификаторам соединений в заголовке пакета выше.
В то же время эффективность была заботой на протяжении всего процесса проектирования QUIC и HTTP/2, поскольку время передачи небольших объектов в HTTP значительно зависит от объема накладных расходов на заголовок. Отсюда и использование кодировок с переменной длиной, которые сохраняют поля небольшими, когда дополнительная длина не требуется.
Вероятно, также справедливо сказать, что обработка невыровненных полей в программном обеспечении сейчас вызывает гораздо меньше беспокойства, чем на вычислительном оборудовании 1970-х годов, поэтому экономия байтов в сети теперь имеет приоритет над 32-битным выравниванием.
Эти длинные идентификаторы соединений заменяют способ идентификации TCP-соединений (исходные и конечные IP-адреса и номера портов TCP) единым идентификатором, уникальным с точки зрения принимающего хоста. Это обеспечивает удобную отправную точку для обеспечения того, чтобы соединения QUIC переживали смену IP-адреса, например, когда хост переключается с одной сети на другую.
Поскольку QUIC отличается от TCP многими способами, большими и малыми, и охватывает четыре RFC, попытка описать его наиболее важные особенности сродни притче о слепых людях и слоне. Один аспект, который привлекает мое внимание, — это то, как была переработана многоуровневость с TLS в QUIC (ранее обсуждалось здесь). Вот схема, которую мы используем для демонстрации этого:
Как была переработана многоуровневость с TLS в QUIC
HTTP поверх TLS был традиционным многоуровневым подходом: TCP предоставляет надежный поток байтов; TLS обеспечивает защищенный канал поверх TCP; а HTTP отправляет прикладные данные по этому защищенному каналу.
QUIC, напротив, поглощает слой записей TLS, при этом рукопожатие TLS настраивает защищенный канал, а HTTP затем может работать непосредственно поверх защищенного канала QUIC. Такой более интегрированный подход позволил сократить несколько круговых задержек (RTT) установки соединения до одного RTT, с возможностью отправки прикладных данных при первом RTT. Как я обсуждал несколько месяцев назад, данные 0-RTT являются хорошим примером сложного компромисса между производительностью и безопасностью. Даже без данных 0-RTT переработанные уровни QUIC и TLS уменьшают количество RTT, необходимых для установки защищенного канала, тем самым обеспечивая реальную выгоду в производительности для приложения.
Наконец, Протокол для RPC
Функция QUIC, на которой я сосредоточился на этот раз, — это поддержка потоков в рамках одного соединения. Это особенно актуально, поскольку мы с Ларри решили поместить QUIC в нашу главу о протоколах «Запрос/Ответ».
Как мы утверждали с первого издания, парадигма «запрос/ответ» плохо подходит для абстракции надежного потока байтов, предоставляемой TCP. Таким образом, хотя QUIC обычно представляется как транспортный протокол для повышения производительности веб-приложений (чем он и является), мы рассматриваем его как долгожданный ответ на вопрос: «Где протокол для приложений „запрос/ответ“?»
Хотя примером «запрос/ответ», который мы склонны использовать, являются удаленные вызовы процедур (RPC), многие аналогичные аргументы применимы и к получению веб-страниц. В частности, как правило, не требуется, чтобы ответы на серию запросов объектов приходили по порядку; важно, чтобы они все приходили быстро. Более того, HTTPS — это не просто протокол для получения веб-страниц; он также лежит в основе протоколов RPC, таких как gRPC, что еще больше подчеркивает необходимость того, чтобы стек протоколов под HTTP был хорошо настроен для RPC.
Потоки являются основным механизмом, который делает QUIC более подходящим для операций «запрос/ответ». Когда HTTP работает поверх TCP, единственный способ позволить одному запросу выполняться независимо от другого — это открыть несколько параллельных TCP-соединений.
При том, что каждое соединение имеет свой собственный цикл управления перегрузкой, опыт перегрузки на одном соединении не очевиден для других соединений; каждое соединение пытается самостоятельно определить соответствующий объем пропускной способности для потребления, конкурируя с другими. И если HTTP работает поверх одного TCP-соединения, потеря одного пакета блокирует весь прогресс любых выполняющихся запросов до тех пор, пока этот потерянный пакет не будет повторно передан.
Таким образом, QUIC позволяет использовать множество потоков в рамках одного соединения, и каждый поток может независимо от других продвигаться вперед. Потеря одного пакета влияет только на поток (или потоки), данные которого находились в этом пакете. В то же время QUIC может использовать эту потерю одного пакета для адекватного реагирования на перегрузку. Потоки предоставляются механизмом, который помещает кадры потока (Stream frames) в пакеты, а процесс запуска потока легок: любой конец соединения может инициировать новый поток, выбрав новый идентификатор потока (Stream Identifier) и отправив кадр с этим идентификатором и первый кадр данных.
То, как QUIC обрабатывает перегрузку и потерю пакетов, заслуживает отдельного RFC (9002), и есть некоторые интересные детали в том, чем QUIC отличается от TCP, в основном в том, как порядковые номера относятся к пакетам, а не к байтам, и никогда не используются повторно, даже для повторных передач. SACK более обширен, допуская больше пробелов в наборе подтвержденных пакетов. Но подход по умолчанию очень похож на TCP NewReno, при этом допускаются и другие варианты.
Сведение сотен страниц RFC к разделу учебника означает, что мы неизбежно должны опускать некоторые детали. Я даже не уверен, будет ли наша книга о всей сетевой работе такой же объемной, как полный набор RFC QUIC. Но, отстаивая с 1990-х годов необходимость в третьем транспортном протоколе, который не является ни UDP, ни TCP, мы рады наконец иметь кандидата на это место, который, похоже, набирает реальную популярность в Интернете.
Конечно, в прошлом было много других усилий по дополнению дуополии TCP/UDP, и SCTP был доблестным усилием, но у QUIC есть много преимуществ. Команда, работавшая над ним с 2012 года, уделила пристальное внимание соображениям развертывания (поэтому он работает поверх UDP — дуополия живет благодаря middlebox’ам). И благодаря тщательно продуманному дизайну QUIC действительно изменил производительность веба и других приложений, требующих семантики «запрос/ответ». ®
Ларри Петерсон и Брюс Дэви — авторы книги Computer Networks: A Systems Approach и связанной серии книг Systems Approach. Весь их контент является открытым исходным кодом и доступен бесплатно на GitHub. Вы можете найти их в Mastodon, их новостную рассылку прямо здесь и прошлые колонки в The Registerздесь.
Всегда имейте в виду, что редакции могут придерживаться предвзятых взглядов в освещении новостей.
Автор – Bruce Davie