Motywacja do Zmian: Ostatnie Wąskie Gardło
Ewolucja z HTTP/1.1 do HTTP/2 była monumentalnym krokiem naprzód w dziedzinie wydajności sieci. HTTP/2 wprowadził multipleksowanie, umożliwiając równoczesne wysyłanie wielu żądań i odpowiedzi przez jedno połączenie TCP, co doskonale rozwiązało problem blokowania na czele kolejki na poziomie aplikacji. Wolne żądanie o duży obrazek nie blokowało już szybkiego pobierania pliku CSS. Jednakże, naprawiając ten problem, społeczność internetowa wkrótce odkryła głębsze, bardziej fundamentalne wąskie gardło: blokowanie na czele kolejki w warstwie transportowej, nieodłącznie związane z architekturą protokołu .
TCP gwarantuje niezawodne i uporządkowane dostarczanie pakietów danych. Jest to kluczowa cecha dla wielu aplikacji, zapewniająca, że pliki nie są uszkodzone, a dane docierają zgodnie z zamierzeniami. Aby to osiągnąć, TCP traktuje wszystkie dane w ramach jednego połączenia jako jeden uporządkowany strumień. Jeśli pojedynczy pakiet zostanie utracony w tranzycie, TCP wstrzyma dostarczanie wszystkich kolejnych pakietów, nawet tych należących do innych, niezależnych strumieni HTTP/2 do czasu, aż utracony pakiet zostanie retransmitowany i odebrany. Oznacza to, że pojedynczy utracony pakiet z pobieranego obrazu mógłby zamrozić renderowanie całkowicie oddzielnego pliku JavaScript na tym samym połączeniu.
To blokowanie HOL na poziomie TCP jest szczególnie szkodliwe w sieciach niestabilnych lub o wysokim opóźnieniu, takich jak sieci komórkowe. W miarę jak coraz więcej osób na świecie korzysta z internetu na urządzeniach mobilnych, to ograniczenie stawało się coraz bardziej znaczące. Stało się jasne, że aby uczynić sieć szybszą i bardziej odporną, sama podstawa jej transportu wymagała przeprojektowania. Ta konieczność była głównym motorem napędowym powstania HTTP/3.
Zmiana Paradygmatu: Budowa na UDP z wykorzystaniem QUIC
HTTP/3 nie działa na protokole TCP. Wykorzystuje , czyli nazwę protokołu, a nie skrót od wyrażenia Quick UDP Internet Connections.
Aby zrozumieć, dlaczego jest to tak znacząca zmiana, musimy najpierw zrozumieć protokół, na którym opiera się QUIC, czyli UDP. jest minimalistycznym, bezpołączeniowym protokołem. Pozwala aplikacjom wysyłać do siebie pakiety (zwane datagramami), ale nie oferuje żadnych gwarancji. Pakiety mogą zostać utracone, zduplikowane lub dotrzeć w innej kolejności. To jak wysyłanie serii pocztówek; niektóre mogą zaginąć, a te, które dotrą, niekoniecznie pojawią się w kolejności, w jakiej zostały wysłane.
QUIC bierze szybkość i prostotę UDP i buduje na nich warstwę niezawodności, w zasadzie reimplementując najlepsze cechy TCP, ale bez jego największych wad. Oferuje niezawodność, kontrolę przeciążenia i kontrolę przepływu, ale robi to w sposób zoptymalizowany dla nowoczesnej, zmultipleksowanej natury HTTP.
Główna Korzyść 1: Eliminacja Blokowania HOL w Warstwie Transportowej
QUIC usuwa blokowanie czoła kolejki pomiędzy niezależnymi strumieniami. Utrata pakietu zawierającego dane jednego strumienia nie zatrzymuje dostarczania danych z pozostałych strumieni. Brakujące bajty nadal wstrzymują jednak uporządkowane dostarczenie w obrębie tego samego strumienia.
W HTTP/2 nad TCP koncepcja strumieni istnieje tylko na poziomie aplikacji. Sam protokół TCP jest ich nieświadomy i widzi tylko pojedynczy, monolityczny strumień bajtów. W przeciwieństwie do tego, QUIC zarządza wieloma niezależnymi strumieniami logicznymi w ramach jednego połączenia. Pakiety danych przesyłane przez sieć są oznaczane identyfikatorem strumienia QUIC, do którego należą.
Jeśli pakiet zawierający dane dla strumienia 3 zostanie utracony, mechanizm niezawodności QUIC wie, że ma wstrzymać dostarczanie danych tylko dla strumienia 3, do czasu retransmisji tego pakietu. Strumienie 1 i 5, których pakiety zostały pomyślnie odebrane, mogą być nadal dostarczane do warstwy aplikacji i natychmiast przetwarzane. To niezależne obsługiwanie strumieni sprawia, że połączenie jest znacznie bardziej odporne na utratę pakietów, zapewniając znacznie płynniejsze i szybsze doświadczenie użytkownika, zwłaszcza w sieciach mobilnych i o dużej stratności.
Główna Korzyść 2: Szybsze Ustanawianie Połączenia
Kolejną znaczącą poprawą wydajności w HTTP/3 jest radykalnie skrócony czas nawiązywania połączenia, co również jest zasługą QUIC. W świecie HTTP/2 nad TCP, ustanowienie bezpiecznego połączenia wymagało dwóch oddzielnych, sekwencyjnych uzgodnień (handshakes):
- Uzgadnianie TCP: Wymaga jednego pełnego obiegu (round-trip) między klientem a serwerem (SYN -> SYN-ACK -> ACK).
- Uzgadnianie TLS: Wymaga jednego do dwóch dodatkowych obiegów w celu negocjacji kluczy szyfrujących.
W rezultacie, zanim pierwszy bajt rzeczywistych danych aplikacji może zostać wysłany, mijają dwa do trzech obiegów. W sieciach mobilnych o wysokich opóźnieniach, to początkowe opóźnienie może być znaczące.
Uzgadnianie 1-RTT i 0-RTT w QUIC
QUIC usprawnia ten proces, łącząc uzgadnianie transportowe i kryptograficzne w jedną procedurę.
- Połączenie 1-RTT: Dla nowego połączenia, klient wysyła komunikat
ClientHello, a serwer może odpowiedzieć komunikatem zawierającym swój certyfikat TLS i wszystkie niezbędne parametry do ustanowienia bezpiecznej sesji. Klient może to następnie zweryfikować i rozpocząć wysyłanie zaszyfrowanych danych. Cały proces zajmuje zazwyczaj tylko jeden czas obiegu (). - Wznowienie połączenia 0-RTT: klient znający serwer może wysłać wczesne dane aplikacji wraz z pierwszym komunikatem uzgadniającym. Dane 0-RTT nie mają ochrony przed powtórzeniem przez napastnika, dlatego serwer może je odrzucić, a klient powinien ograniczyć je do operacji bezpiecznych przy ponownym wykonaniu. Mechanizm skraca oczekiwanie na rozpoczęcie transmisji, ale nie usuwa opóźnienia sieci ani czasu przetwarzania żądania.
Główna Korzyść 3: Migracja Połączenia dla Świata Mobilnego
Jedną z najbardziej zauważalnych dla użytkownika innowacji QUIC jest jego odporność na zmiany sieciowe, funkcja znana jako migracja połączenia. Tradycyjne połączenie TCP jest ściśle zdefiniowane przez 4-krotkę: źródłowy adres IP, port źródłowy, docelowy adres IP i port docelowy. Jeśli którakolwiek z tych czterech wartości się zmieni, połączenie zostaje przerwane.
Tworzy to frustrujące doświadczenie użytkownika w świecie zdominowanym przez urządzenia mobilne. Wyobraź sobie, że oglądasz film na telefonie w domu, połączony z siecią Wi-Fi. Wychodząc z domu i tracąc zasięg, Twój telefon płynnie przełącza się z Wi-Fi na sieć komórkową. Kiedy to się dzieje, zmienia się adres IP Twojego telefonu. Z perspektywy TCP, narusza to 4-krotkę, a istniejące połączenie z serwerem wideo zostaje natychmiast zakończone. Odtwarzacz wideo musi buforować, ustanowić całkowicie nowe połączenie TCP i TLS przez sieć komórkową i wznowić strumień, co powoduje zauważalne zacięcie lub przerwę.
QUIC rozwiązuje ten problem w elegancki sposób. Zamiast identyfikować połączenie za pomocą adresów IP i portów, QUIC używa . Jest to unikalny identyfikator dołączany do nagłówka każdego pakietu QUIC. Kiedy Twój telefon przełącza się z Wi-Fi na sieć komórkową, zmienia się Twój adres IP, ale Identyfikator Połączenia pozostaje taki sam. Możesz kontynuować wysyłanie pakietów z tym samym Identyfikatorem Połączenia ze swojego nowego adresu IP. Serwer, widząc ten znajomy identyfikator, wie, że to to samo, trwające połączenie i płynnie kontynuuje transfer danych. Dla użytkownika, strumień wideo jest kontynuowany bez przerw, zapewniając prawdziwie płynne doświadczenie mobilne.
Warstwa Aplikacji w HTTP/3
Chociaż warstwa transportowa została całkowicie wymieniona, warstwa aplikacji w HTTP/3 zachowuje te same semantyki i funkcje wysokiego poziomu wprowadzone w HTTP/2. Koncepcje żądania/odpowiedzi, nagłówków, metod (GET, POST, itp.) i kodów statusu pozostają niezmienione. Funkcje takie jak Server Push i priorytetyzacja strumieni również są obecne w HTTP/3, ponieważ są one implementowane na poziomie HTTP.
Mapowanie HTTP na Strumienie QUIC
Kluczową różnicą jest sposób mapowania tych koncepcji na podstawowy transport. QUIC zapewnia natywną abstrakcję strumienia, więc każda para żądanie-odpowiedź HTTP/3 jest mapowana na dedykowany strumień QUIC. Jest to znacznie czystsze i bardziej wydajne mapowanie niż implementacja strumieni na poziomie aplikacji, która była nakładana na TCP w HTTP/2.
QPACK: Kompresja Nagłówków dla QUIC
Kompresja nagłówków pozostaje kluczową funkcją. Jednak schemat kompresji HPACK z HTTP/2 opierał się na ścisłym, uporządkowanym dostarczaniu danych przez TCP. Ponieważ strumienie QUIC mogą dostarczać dane w innej kolejności, potrzebny był nowy schemat kompresji. HTTP/3 używa QPACK, który jest podobny w założeniach do HPACK, ale został zaprojektowany do pracy z bardziej elastycznym modelem dostarczania QUIC. Używa on oddzielnych, jednokierunkowych strumieni do zarządzania dynamicznymi tabelami nagłówków, co zapobiega blokowaniu HOL w samym mechanizmie kompresji nagłówków.
Wdrożenie i Przyszłość
HTTP/3 jest opublikowanym standardem opisanym w RFC 9114 z 2022 roku. Jest obsługiwany przez główne przeglądarki, serwery i sieci dostarczania treści, ale administrator nadal musi skonfigurować QUIC oraz ruch UDP do portu usługi.
QUIC może być blokowany przez zapory lub urządzenia pośredniczące, które nie dopuszczają ruchu UDP do portu . Klient wykrywa obsługę HTTP/3 między innymi na podstawie informacji Alt-Svc, rekordów HTTPS DNS, zapamiętanych danych o serwerze i własnej konfiguracji. Pierwsza wizyta nie zawsze zaczyna się więc próbą HTTP/3. Jeżeli QUIC jest niedostępny, klient może użyć HTTP/2 lub HTTP/1.1 przez TCP, zależnie od obsługi po obu stronach.