Сегодня речь пойдет о HTTP/3 — новом сетевом стандарте, который заметно оживил интернет. Так ли он быстр, как о нем говорят, и в чем его главные отличия от устоявшихся стандартов — попробуем разобраться в этой статье.
Содержание:
1. История стандарта HTTP
2. Блокировка начала очереди
3. 0-RTT
4. Congestion Control — управление перегрузкой
5. Миграция IP
6. Сжатие заголовков QPACK
7. Раздувание буфера
8. Имплементации QUIC
Заключение
Более тридцати лет назад, с подачи сэра Тимоти Джона Бернерс-Ли вышла прото-версия HTTP/0.9. В ней был всего лишь GET-метод и не было заголовков. В мае 1996 года появилась уже HTTP/1.0. В этой версии уже присутствовали новые методы, заголовки и кэширование.
Еще через три года в 1999 появился стандарт HTTP/1.1. Появился keep-alive
и главное изменение — заголовок Host
, который позволял организовывать виртуальный хостинг, который позволял с одного адреса делать несколько доменов на одном IP. С этого момента началось активное развитие интернета.
В феврале 2015 года вышел новый стандарт — HTTP/2, прародителем которого стал протокол прикладного уровня для передачи веб-контента SPDY. Протокол HTTP/2 стал бинарным, появилось сжатие заголовков (HPACK), мультиплексирование и приоритезация ресурсов, а также опция отмены загрузки и Server Push. Благодаря мультиплексированию появилась возможность отправлять несколько файлов за раз и даже как-то их приоритезировать (в большинстве случаев браузер сам молча принимает решение, какая должна быть приоритезация при загрузке).
С выходом HTTP/2 все ожидали революционных перемен в скорости работы сайтов. Но на практике выяснилось, что большинство фич реализованы не лучшим образом. И управление потоками и приоритетами, и технология Server Push для отправки совместимому клиенту ресурсов — на деле оказались не такими и эффективными.
В конце двухтысячных годов стало заметно, что основной транспортный протокол TCP уже начал устаревать. Ему на смену пришел радикально новый протокол QUIC (иногда пишется как gQUIC, чтобы подчеркнуть активное участие Google в разработке), по сути являющийся надстройкой для UDP. QUIC по-сути и стал стандартом HTTP/3.
За тридцать лет TCP практически не менялся. На физическом уровне скорость стала быстрее, однако стабильности за это время не прибавилось. В поисках альтернативы разработчики остановили свое внимание на UDP. В отличие от TCP, протокол UDP не гарантирует целостность пакетов — мы просто пересылаем данные и понятия не имеем, дошел пакет или нет. Для того, чтобы гарантировать и оптимизировать доставку пакетов, в TCP используется масса параметров, в то время как в UDP задействуется только порты получения и назначения, длина данных и контрольная сумма.
В UDP не требуется рукопожатие для установки соединения и в нем отсутствует эффект head-of-line, о котором речь пойдет ниже. То есть это более легкий и простой (а, значит, потенциально более шустрый) протокол в сравнении с навороченным TCP.
Если мы сравним протоколы TCP и QUIC по стеку, то мы увидим, что QUIC-реализация по USER SPACE размазана по трем слоям: Application, Security и Transport. На сетевом уровне у нас есть IP, над ним — UDP, а уже выше работает QUIC.
Контроль перегрузки TCP Congestion Control, механизмы восстановления loss recovery, а также Seсurity и мультистриминг переехали на уровень пользовательского пространства. Это гарантирует быстрое обновление и дальнейшее развитие протокола.
Примерно уже с 2012 года стало очевидным, что сети развиваются в сторону беспроводных технологий, что накладывает некоторые ограничения на качество передачи данных. Беспроводные сети отличаются высокой скоростью, но при этом имеют низкую стабильность сигнала.
Например, одна из проблем — потеря пакетов Packet Loss. Беспроводные технологии 3G, 4G, LTE — чаще используются на улице, где есть переотражения сигнала, что приводит к регулярной потере пакетов. Кроме того, на качество сигнала в этих сетях оказывают влияние локальные сети Wi-Fi и Bluetooth-соединения, что также приводит к потере данных.
Кроме того, нет никаких гарантий, что пакеты, посланные в определенном порядке, так и придут — они могут меняться местами на этапе получения.
Еще одна проблема передачи данных в беспроводных сетях — джиттер, то есть случайная задержка между пакетами. Из-за этих задержек страдает качество связи, и, возможна ситуация, когда клиент доподлинно не знает, получен ли пакет (из-за чего данные запрашиваются заново, это так называемый retrain).
Все это порождает такое неприятное явления как блокировка начала очереди — head-of-line. В HTTP/2 с описанными выше проблемами (джиттером, потерей пакетов, ритрейнами и нарушением очередности) боролись на уровне запросов, а не на уровне транспортного протокола.
Например, мы посылаем в TCP-канал какие-то данные, и, если один пакет потерялся, на выходе мы ничего не получаем. В этом случае TCP либо перезапрашивает пакет, либо проходит какое-то время и данные посылаются снова.
Однако, до тех пор, пока данные не будут повторно получены, мы не можем получить доступ к файлам, которые уже находятся в буфере на нашем компьютере.
Проблема head-of-line решается в QUIC следующим образом. В отличие от протокола TCP, где передача файлов идет одним потоком, в QUIC применяются отдельные стримы. Потеря отдельного пакета в TCP приводит к тому, что весь стрим оказывается бесполезным и отбрасывается. В QUIC же, если какой-то отдельный пакет пропадет, на выходе мы все равно получим некоторое количество успешных потоков с которыми можно работать (и один неполный поток, который можно отдельно отретрейнить).
QUIC обеспечивает 0-RTT (zero round-trip time) — максимально быстрое установление сессии. Для установки соединения TCP использует процесс, называемый термином «трехстороннее рукопожатие». Суть его состоит в следующем.
Клиент посылает сегмент с флагом SYN. Сегменту присваивается произвольный порядковый номер (sequence number) в интервале от 1 до 232, относительно которого будет вестись дальнейший отсчет последовательности сегментов в соединении.
Далее сервер получает запрос и отправляет ответный сегмент с одновременно установленными флагами SYN+ACK. При этом в поле «номер подтверждения» устанавливается полученный порядковый номер, увеличенный на 1 (что подтверждает получение первого сегмента), а также устанавливает свой порядковый номер, который, как и в SYN-сегменте, выбирается произвольно.
После получения клиентом сегмента с флагами SYN+ACK — соединение считается установленным и клиент возвращает сегмент с флагом ACK и обновленными номерами последовательности. Рукопожатие считается завершенным и осуществляется передача данных.
Кроме того QUIC глубоко интегрирован с TLS и объединяет транспортное и криптографическое рукопожатие в одно, сокращая число циклов приема-передачи. Порядковые номера пакетов никогда не используются повторно при повторной передаче пакета. Это позволяет избежать двусмысленности в отношении того, какие пакеты были получены, а также избежать ужасных тайм-аутов повторной передачи.
Как следствие — QUIC превосходит TCP при неблагоприятных условиях связи в сети, сокращая время загрузки страницы поиска Google на целую секунду для 1% самых медленных подключений. Еще более очевиден прирост в скорости на таких видеосервисах, как YouTube.
В новой версии протокола есть новые варианты Congestion Control — управление перегрузкой. Механизмы flow-control и congestion-control не дают отправителю перегрузить сеть или получателя, но замедляют TCP по сравнению с «чистым» UDP. Стандарт QUIC не обязывает вас использовать какой-то конкретный Congestion Control (по умолчанию реализован тип NewReno, который относительно просто можно настроить).
В Chrome у нас используется Cubic, также применяется BBR, продвигаемый Google, который чуть лучше работает в сетях с высоким процентом потери пакетов. Loss Recovery неотъемлемо связан с Congestion Control. В случае с QUIC Loss Recovery мы не ждем повторной пересылки данных, а сразу запрашиваем целостность последних пакетов — дошли или нет. До того, как произойдет ретрансмит пакета, мы можем успеть сделать до двух запросов tail loss.
Когда вы ходите по улицам с мобильным телефоном или куда-то едете, вы постоянно переключаетесь от точки к точке, вследствие чего часто меняется IP-адрес. В TCP коннект определяется несколькими параметрами: IP-адресами отправителя и сервера, а также номерами портов для сервера и клиента. Как только какой-то из этих параметров изменился, соединение автоматически разрывается.
В случае же с QUIC у нас нет конкретного соединения, все реализовано на уровне отправки пакетов и идентификатора соединения CID. Клиент и сервер просто ориентируются на значение CID, поэтому между сетями возможна прозрачная миграция — участники «узнают» друг друга и состояние загрузки (даже после переподключения) остается прежним.
В целях безопасности при каждом переходе в новую сеть QUIC меняет CID. Для этого используется общий (для клиента и сервера) список случайно сгенерированных значений.
Вместо HPACK в версии HTTP/3 появился QPACK. QPACK — это тот же самый способ сжатия заголовков для HTTP/3. Отличие только в том, что в случае с HTTP/2 логика сжатия была завязана на том, что у нас был один стрим и все пакеты приходили по порядку.
В HTTP/3 у нас много стримов, и, для того чтобы оптимизировать сжатие, нам нужно объединить все эти стримы и создать одну общую таблицу для сжатия (в HPACK это просто не было предусмотрено).
Следующая проблема — излишняя сетевая буферизация. Как известно, пропускная способность сетевого канала непостоянна. Чтобы отдавать данные с максимальной скоростью канала, необходимо увеличивать буфер (чтобы в него помещать столько пакетов, сколько может быть отправлено в единицу времени).
В результате низкоприоритетный запрос забивает канал и зачастую не дает отправиться более приоритетным данным — происходит раздувание буфера или Bufferbloat Effect. Например, когда вы посылаете сначало большое видео, а затем решили послать более приоритетный запрос от API, то последний запрос на какие-то секунды подвисает.
При отправке видео у нас так вырастает буфер, что возможности для отправки короткого API уже нет. Данные ставятся в конец очереди и отправятся лишь тогда, когда все пакеты из буфера будут сброшены.
В логике работы TCP нет возможности влиять каким-то образом на буфер и, скажем, удалять оттуда какие-то пакеты, приоритизировать или перемещать их.
Подведем итоги. Строго говоря, версия HTTP/3 представляет собой исправленный вариант HTTP/2, в котором обеспечена совместимость с QUIC. Поэтому между HTTP/1.1 и HTTP/2 различий гораздо больше, чем между HTTP/2 и HTTP/3.
HTTP/3 заметно быстрее и позволяет использовать всю ширину канала. В обновленном протоколе меньше служебной информации — соответственно, соединение работает быстрее (особенно заметно при передаче мелких файлов, при использовании потоковых видеосервисов типа Youtube). Соединение более стабильное и не обрывается — человек на сотовой связи может переключаться на Wi-Fi без обрыва загрузки.
Недостатки тоже есть и сводятся, главным образом, к тому, что вся реализация протокола выполнена не на уровне ядра, «железок» и сети, а на уровне User Space. Кроме того, минусом можно считать уязвимость UDP-протокола к DDOS-атакам и различного флудинга.
Поскольку QUIC работает поверх UDP, потребуется его разрешение для входящего и исходящего трафика HTTP/3-серверов, по умолчанию это 443 порт.
В процессе использования HTTP/3 может возникнуть ситуация, когда или принимающий сервер не поддерживает QUIC, либо какая-то из промежуточных сетей или файрволов блокирует QUIC и/или UDP. Очевидно, чтобы избежать задержек, следует использовать сразу два соединения (QUIC и TCP).
В завершение статьи рекомендуем вам посмотреть познавательное видео про то, как правильно настроить этот новый протокол, а также про минусы и плюсы перехода на HTTP/3 QUIC:
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…