Web

HTTP/2

Ramkowanie binarne, multipleksowanie i server push w HTTP/2.

Dlaczego potrzebny był nowy HTTP? Ograniczenia HTTP/1.1

Przez prawie dwie dekady protokół HTTP/1.1 stanowił podstawę rozwoju World Wide Web. Wprowadził on połączenia trwałe, pozwalając na wysyłanie wielu żądań i odpowiedzi przez jedno połączenie TCP, co stanowiło istotną zmianę w stosunku do jego poprzednika, HTTP/1.0. Jednak w miarę jak strony internetowe ewoluowały z prostych dokumentów tekstowych w złożone, bogate w zasoby aplikacje z dziesiątkami skryptów, arkuszy stylów i obrazów, ograniczenia HTTP/1.1 zaczęły ograniczać wydajność.

HTTP/1.0 pozwalał na jedno oczekujące żądanie w ramach połączenia. HTTP/1.1 dodał pipelining, lecz klienci często otwierali kilka połączeń, aby zwiększyć współbieżność. Połączenia te konkurowały o mechanizmy kontroli przeciążenia i zasoby gniazd.

Jednym z problemów HTTP/1.1 jest tak zwane . Trwałe połączenie nie zapewniało multipleksowania. Pipelining pozwalał wysłać kilka żądań przed otrzymaniem odpowiedzi, lecz odpowiedzi musiały zachować kolejność. Powolne żądanie, na przykład o duży obraz lub wolno działający punkt końcowy API, mogło więc opóźnić kolejne odpowiedzi i renderowanie strony.

Stosowano obejścia tego problemu, takie jak używanie wielu połączeń TCP do jednej nazwy hosta, fragmentacja domen czy łączenie plików. Te techniki dodawały złożoności i narzutu. Z czasem stało się jasne, że protokół wymaga przeprojektowania, aby sprostać wymaganiom nowoczesnej sieci. To doprowadziło do rozwoju HTTP/2, który w dużej mierze opierał się na eksperymentalnym protokole SPDY firmy Google i został oficjalnie ustandaryzowany w 2015 roku.

Koncepcja podstawowa 1: warstwa ramek binarnych

Jedną z najważniejszych zmian wprowadzonych w HTTP/2 jest . HTTP/1.1 używał tekstowej składni komunikatów. Linie żądań i pola były zapisywane jako tekst oddzielany znakami nowej linii, natomiast treść mogła zawierać dowolne oktety. Taki format ułatwiał debugowanie, lecz zwiększał złożoność parsowania.

HTTP/2 dzieli komunikację na mniejsze jednostki zwane ramkami i koduje je binarnie. Ta zmiana ułatwia parsowanie maszynowe oraz obsługę współbieżnych strumieni:

  • Wydajność: format binarny ogranicza narzut parsowania.
  • Jednoznaczność: struktura ramki ogranicza różnice interpretacji składni tekstowej.
  • Obsługa strumieni: ramki można przeplatać na jednym połączeniu.

Struktura ramki HTTP/2

Każda ramka w HTTP/2 ma ściśle zdefiniowaną strukturę. Składa się ze stałego 9-bajtowego nagłówka, po którym następuje ładunek o zmiennej długości. Nagłówek zawiera długość ładunku, typ, flagi, bit zarezerwowany i identyfikator strumienia. Odbiorca ogłasza maksymalny rozmiar ładunku przezSETTINGS_MAX_FRAME_SIZE.

Długość (24 bity)
Wskazuje długość ładunku ramki w bajtach.
Typ (8 bitów)
Definiuje typ ramki i sposób interpretacji ładunku.
Flagi (8 bitów)
Zestaw flag zależnych od typu ramki.
Pole zarezerwowane (1 bit)
Bit bez zdefiniowanej semantyki, który nadawca pozostawia wyzerowany.
Identyfikator strumienia (31 bitów)
Określa, do którego strumienia należy dana ramka.
Ładunek ramki (zmienny)
Właściwa zawartość ramki, zależna od jej typu.

Popularne typy ramek

Najczęściej spotkasz między innymi:

  • DATA: ciało wiadomości.
  • HEADERS: nagłówki HTTP.
  • PRIORITY: starsza ramka priorytetu strumienia. Jej schemat sygnalizacji jest zdeprecjonowany.
  • SETTINGS: konfiguracja połączenia.
  • PUSH_PROMISE: zapowiedź server push.

Koncepcja podstawowa 2: strumienie i multipleksowanie

Warstwa ramek binarnych umożliwia podstawową funkcję HTTP/2: . Funkcja usuwa blokowanie na poziomie wymiany HTTP/1.1, lecz utrata pakietu TCP nadal może wstrzymać wszystkie strumienie.

Strumienie: wirtualne kanały

W ramach jednego połączenia HTTP/2 klient i serwer mogą ustanowić wiele niezależnych, dwukierunkowych sekwencji ramek zwanych strumieniami. Jedno połączenie TCP przenosi ramki wszystkich strumieni, które mogą dotyczyć HTML, arkusza stylów i obrazu oraz być obsługiwane współbieżnie.

  • Każdy strumień ma własny identyfikator.
  • Żądanie i odpowiedź odbywają się w tym samym strumieniu.
  • Strumienie klienta mają identyfikatory nieparzyste, a serwera parzyste.
  • Jedno połączenie może przenosić setki lub tysiące strumieni naraz.

Strumień 0 jest zarezerwowany dla ramek dotyczących całego połączenia, takich jakSETTINGS iGOAWAY. Ramki DATA podlegają kontroli przepływu dla strumienia i dla całego połączenia, dlatego nadawca musi respektować okna ogłoszone przez odbiorcę.

Jak multipleksowanie usuwa blokowanie HOL

Ponieważ komunikacja jest podzielona na małe ramki, serwer może przeplatać odpowiedzi z wielu strumieni na tym samym połączeniu. Na poziomie HTTP opóźnienie jednego dużego zasobu nie blokuje innych odpowiedzi, więc CSS, JS i małe zasoby mogą dotrzeć szybciej. Utrata pakietu TCP nadal wstrzymuje dostarczanie ramek wszystkich strumieni do czasu retransmisji.

W rezultacie zmniejsza się potrzeba stosowania obejść, takich jak wielokrotne połączenia do jednego hosta. Efektem może być szybsze ładowanie stron, mniejsze zużycie zasobów i lepsze wykorzystanie sieci.

Koncepcja podstawowa 3: wypychanie serwerowe (Server Push)

W klasycznym HTTP to klient inicjuje komunikację. Pobiera HTML, analizuje go i dopiero potem żąda CSS oraz JavaScriptu. To tworzy kaskadę żądań i opóźnień.

HTTP/2 dodał mechanizm , w którym serwer może przewidzieć potrzebne zasoby i wysłać je z wyprzedzeniem.

Jak działa Server Push

  1. Żądanie klienta: przeglądarka prosi o index.html.
  2. Analiza serwera: serwer wie, że zaraz potrzebne będą też style.css i app.js.
  3. PUSH_PROMISE: serwer zapowiada i wysyła te zasoby, zanim klient o nie poprosi.
  4. Oryginalna odpowiedź: klient nadal dostaje żądany HTML.
  5. Buforowanie po stronie klienta: przeglądarka może użyć zasobów od razu podczas renderu.

Server Push może skrócić czas ładowania, lecz wymaga kontroli stanu pamięci podręcznej klienta. Wypychanie zasobów już obecnych w cache zwiększa zużycie sieci, dlatego wdrożenia często korzystają z podpowiedzi preload.

Wypychana odpowiedź jest związana z syntetycznym żądaniem i podlega semantyce odpowiedzi HTTP, w tym regułom cache. Klient może anulować wypychanie, gdy zasób nie jest potrzebny.

Inne usprawnienia w HTTP/2

Poza trzema głównymi koncepcjami HTTP/2 wprowadził jeszcze kilka usprawnień wpływających na wydajność.

Kompresja nagłówków (HPACK)
HPACK używa tablicy statycznej i dynamicznej, aby zwięźlej kodować powtarzające się pola przy kolejnych żądaniach. Stan kompresji jest utrzymywany dla połączenia, a blok pól może obejmować ramki HEADERS i CONTINUATION.
Priorytetyzacja strumieni
Klient może zasugerować, które zasoby są ważniejsze dla renderowania. Starsze drzewo priorytetów jest zdeprecjonowane, a sygnał priorytetu pozostaje sugestią bez gwarancji kolejności dostarczenia.
Jedno połączenie na domenę
Multipleksowanie zmniejsza potrzebę otwierania wielu połączeń TCP do tego samego hosta. Klient może jednak utworzyć więcej niż jedno połączenie zależnie od konfiguracji, certyfikatu i warunków sieciowych.
Domyślnie bezpieczny w praktyce
Specyfikacja dopuszcza HTTP/2 bez TLS, lecz dla URI https protokół jest negocjowany przez TLS z identyfikatorem ALPN h2.

Powiązane artykuły