Hlavní navigace

HTTP/3: co nám nový protokol přinese a proč to hned tak nebude

25. 2. 2019
Doba čtení: 12 minut

Sdílet

Patnáct let se toho u protokolu HTTP moc nedělo, pak přišly v rychlém sledu novinky v podobě SPDY, HTTP/2, QUIC a nově HTTP/3. Co nám nové protokoly přinesou a proč se jich nedočkáme rychle?

Původní textový protokol HTTP/1 byl standardizován v roce 1996, jeho novější revize HTTP/1.1 pak v roce 1999. Mezi tím se s protokolem nedělo nic dramatického, až v roce 2015 byl standardizován HTTP/2.0, což je ovšem v zásadě úplně jiný protokol. Rozjel se velmi pěkně a dnes je široce využíván. Prohlížeče ho používají častěji než HTTP/1.1, řekl Daniel Stenberg na své přednášce na konferenci FOSDEM 2019. Dalším krokem je protokol HTTP/3, který opět zásadně mění pravidla hry.

Daniel Stenberg pracuje na síťových protokolech přes dvacet let, dříve také jako zaměstnanec organizace Mozilla. Nejznámější je svým projektem cURL, což je knihovna a zároveň utilita pro přenos dat pomocí různých protokolů.

HTTP bylo původně postaveno na protokolu TCP, který se dá docela dobře připodobnit k řetězu složenému z jednotlivých článků – v tomto případě paketů. Při zahájení komunikace se nejprve pomocí třícestného handshake sestaví spojení a poté se vyměňují pakety s daty, přičemž ty ztracené se mohou zopakovat. Vzniká jakýsi datový proud, odesíláte data a druhá strana je přijímá. To je princip protokolu TCP, který byl vytvořen už velmi dávno.

Daniel Stenberg na FOSDEM 2019

Dnes ovšem používáme HTTPS, což do tohoto schématu přidává ještě protokol TLS. Nad TCP se postaví TLS a do něj se teprve balí HTTPS. Je to dnes nejběžnější způsob, který se dnes používá zhruba při 80 % spojení. TLS vlastně přidává nad TCP bezpečnostní vrstvu, která přidává ještě více komunikace a dalších handshaků. V TLS 1.3 je to trochu lepší, není potřeba přenášet tolik paketů, ale přesto to znamená komunikaci navíc, říká Stenberg. Důležitější ale je, že přináší soukromí a bezpečnost – můžeme si být jisti identitou serveru na druhé straně a také tím, že naši komunikaci nemůže nikdo odposlouchávat. Uvnitř je ale stále protokol HTTP.

HTTP/1.1

Kvůli zvýšení efektivity u HTTP/1.1 používají prohlížeče obvykle několik různých TCP spojení pro paralelní stahování obsahu ze serveru. Typicky jde o šest spojení na každé doménové jméno. Protože u velkých webů se používá více domén, probíhá komunikace pomocí mnoha a mnoha TCP spojení. Spojení je využito vždy jen pro jeden požadavek a poté je zavřeno, což je ovšem velmi neefektivní. TCP má totiž pomalou dobu náběhu a chvíli mu trvá, než dosáhne vysoké rychlosti. My ho ale hned zavřeme, takže se nestihne pořádně rozjet. To je jeden z důvodů, proč zvýšením rychlosti připojení obvykle nedosáhneme rychlejšího načítání webových stránek. Spojení se příliš rychle zavírají.

Další problém tohoto přístupu spočívá v blokování požadavků probíhajícími spojeními. Říkáme tomu HTTP head-of-line-blocking a je to stav, kdy máme otevřených šest spojení a sedmý požadavek čeká na dokončení stahování a uvolnění jednoho ze spojení. Prohlížeč tedy velkou část doby čekají, čímž se opět klesá efektivita přenosu a prodlužuje se doba načtení stránky. V průběhu let se objevila spousta způsobů, jak tato omezení obejít. Ty byly brány v potaz při návrhu nové generace protokolu.

HTTP/2

Druhá verze protokolu byla vytvořena tak, aby odstraňovala právě tyto nejpalčivější problémy. Stačí jí jedno TCP spojení na každé doménové jméno, protože dokáže řídit mnoho paralelních toků uvnitř jednoho spojení. Typicky je to až stovka přenosů uvnitř jednoho spojení. Můžete si vyjednat víc, ale stovka je dostatečné množství pro všechny běžné situace. Odpadají tak problémy s čekáním na uvolnění spojení, vždy je možné uvnitř existující TCP relace vyslat nový požadavek. Objevuje se nám tu ale zase problém TCP head-of-line-blocking. Když uvnitř jednoho TCP spojení běží stovka přenosů a jednomu z nich vypadne paket, musí se zopakovat. Po tu dobu ovšem zbývající toky čekají, než se provoz obnoví. Dostali jsme se tak z louže pod okap – odstranili jsme jeden problém a druhý jsme vytvořili.

Další problém vznikl kvůli různým krabičkám – zařízením mezi uživatelem a serverem. Ty zahrnují routery, brány, firewally, load ballancery, NATy a další věci, které potřebujeme, aby internet fungoval. Na nich běží software, který ale umí pracovat jen s existujícími protokoly. To způsobuje problém, pokud chceme stávající protokol upravit nebo vytvořit něco úplně nového. Kvůli těmto zařízením je velmi těžké přijít s něčím novým, navíc se velmi těžko aktualizují. Prohlížeč se vám mění téměř každý den nebo týden, stejně tak servery se průběžně aktualizují. Tyhle síťové krabičky jsou ale zaseknuté v čase. Přijít s něčím novým je tedy velmi složité, stejně jako není možné nahradit protokoly TCP a UDP.

Kvůli tomu dnes nikdy neuvidíte HTTP/2 v nešifrované podobě, protože jej právě tato zařízení na síti nerozpoznají a zablokují jej. Proto se HTTP/2 přenáší jen uvnitř TLS, do kterého síťové prvky nemohou zasáhnout. Další problém způsobuje TFO, což je skvělý způsob, jak zrychlit navazování TCP spojení. Bohužel krabičky mu také nerozumí, proto takové pakety mohou zahodit a efekt je opačný – musíte je zopakovat bez TFO a tím se opět zdržujete. Vývojáři Firefoxu s tímto problémem podle Stenberga velmi dlouho bojovali a nakonec se vzdali. TFO je skvělá myšlenka, ale není možné ji implementovat.

QUIC

QUIC je nový transportní protokol, který vznikl navzdory všem těmto síťovým omezením. Stejně jako HTTP/2 vznikl na základě mnoha zkušeností lidí ze společnosti Google. Ti už v roce 2013 ukázali, že je možné poslat protokol HTTP/2 uvnitř protokolu UDP a tím vznikl protokol QUIC. Mají mnoho používaných služeb a jednoho z nejrozšířenějších klientů, takže to mohli dobře odladit a ukázat světu, že to funguje a přináší mnohá zlepšení.

Google se v roce 2015 rozhodl výsledek své práce přinést do IETF a začít se standardizací. Posílat HTTP přes UDP je příliš specifické použití, takže bylo rozhodnuto, že vznikne samostatný transportní protokol a jeho aplikace. QUIC z IETF je proto hodně odlišný od QUIC, který používá Google. Dále se budu zaměřovat na QUIC od IETF, což je věc, na které budeme v budoucnu pracovat.

Když už vzniká nový transportní protokol, je rozumné zbavit se dřívějších problémů jako TCP head-of-line-blocking, pomalý handshake a chybějící mechanismus TFO. Můžeme také zlepšit šifrování, aby byla proti odposlechu chráněna ještě větší část metadat. Síťové prvky pak neuvidí do podstaty komunikace a nebudou ji moci ovlivňovat.

Řekli jsme si, že nemůžeme přijít s úplně novým transportním protokolem a musíme využít ty stávající. Stavíme proto nad UDP, ke kterému se chováme jako k IP. Slouží nám jen k transportu datagramů. Nad UDP je pak potřeba vystavět spolehlivý transportní protokol, který bude implementován plně v uživatelském prostoru. UDP není spolehlivé, ale QUIC je. Přidává spojení, opakování paketů a řízení toku.

QUIC přináší podporu toků (streamů), podobně jako HTTP/2, ale v tomto případě už na transportní vrstvě. To zásadně mění pravidla hry: je sice možné jedním spojením tlačit více různých datových proudů, ty jsou ale najednou nezávislé. Když ztratíte paket, týká se to jen toho jediného toku, ostatní už nemusejí čekat a mohou komunikovat dál. Tím se efektivně zbavujeme problému TCP head-of-line-blocking.

Skutečně nezávislé datové toky díky QUIC

Nad transportním protokolem QUIC pak běží samotné aplikační protokoly. Zatímco původní QUIC počítal jen s HTTP, verze vzniklá v IETF dovoluje využít libovolný aplikační protokol. Ten ovšem může v každém případě těžit z výhod protokolu pod sebou: mají například „zadarmo“ k dispozici zmíněnou podporu toků. V první fázi se pracovalo na kombinaci s HTTP, později se bude pracovat na dalších.

HTTP/3 = HTTP over QUIC

Poslední novinkou v této oblasti je připravovaný standard HTTP/3, který je vlastně aplikací HTTP uvnitř transportního protokolu QUIC. HTTP je sice v principu pořád stejné, ale přesto je jiné. Stále je tu známý požadavek na danou cestu, doplněný hlavičkami a tělem, stejně jako dříve. Na druhé straně zůstává odpověď včetně stavového kódu, hlaviček a opět těla. Tahle část je stejná, ale pod ní se změnilo mnohé.

Protokol HTTP/1.1 je vlastně zasílání ASCII přes TCP a HTTP/2 je binární multiplexovaný protokol posílaný pomocí TCP. HTTP/3 jde vlastně o krok zpět a jde o binární protokol poslaný uvnitř multiplexovaného protokolu QUIC. Implementace je vlastně mnohem jednodušší, protože streamy řeší transportní protokol QUIC. Vrstvy na sobě postavených protokolů teď vypadají úplně jinak:

Vrstvení jednotlivých protokolů

Z hlediska vlastností jde také o hodně odlišné protokoly: HTTP/3 nemůže data přenášet bez šifrování a má zcela nezávislé streamy. Díky tomu může zavést také lepší kompresi hlaviček. Má také výrazně rychlejší handshake, dokonce se umí obejít i bez něj, pokud spolu obě strany už dříve komunikovaly a vyměnily si potřebná data.

Porovnání vlastností obou protokolů

Z toho všeho vyplývá, že by HTTP/3 mělo být především výrazně rychlejší než jeho předchůdci. Bohužel to ještě nedokážeme říct, protože není nikde implementován a můžeme tedy vycházet jen z dat, která má Google pro svůj QUIC. Je to sice jiný protokol, jak bylo řečeno dříve, ale je to také HTTP přenášený pomocí UDP.

Podle údajů změřených Googlem se nový protokol nejvíce projeví těm, kteří mají nejhorší výchozí podmínky. Uživatelům s nejpomalejším připojením (nejhorší 1 %) zkrátí dobu načítání výsledků vyhledávání až o jednu sekundu. Na YouTube se QUIC projevuje o 18 % nižším časem přednačítání (buffering) a 75 % spojení využívá výhod vlastnosti zero-round-trip, kdy při opakovaném navazování spojení není potřeba si vyměňovat žádná data. Velké množství spojení tak navážete velmi rychle, takže jde v praxi o vysoce užitečnou vlastnost. Google také uvádí, že doba načítání výsledků vyhledávání se zkrátí o 3 %. To není moc, ale je to velmi malá stránka.

HTTPS z pohledu HTTP/3

Prohlížení webu pomocí HTTPS je dnes běžnou záležitostí, pokud je před adresou https://, připojuje se prohlížeč pomocí TCP a protokolu TLS na port 443. S příchodem HTTP/3 se to ale možná změní, protože právě tento protokol je připraven na velký upgrade. Zatím v tomhle ohledu nepanuje úplná shoda, ale standard už k tomu zaujímá určité obecné postoje.

Důležitou roli v tom hraje už existující hlavička Alt-Svc, která v zásadě říká: Použij tamten server a komunikuj s ním tímhle protokolem. Je stejný jako já. Je to zavedená hlavička, která se objevila už s HTTP/2. Říká, že komunikace má probíhat s jiným doménovým jménem, portem či s pomocí jiného protokolu, pořád jde ale o stejný zdroj (origin). Můžete tak klientovi ohlásit, že stejná stránka je dostupná také pomocí protokolu HTTP/3 na jiné adrese po dobu následujících N sekund.

Bude to ale fungovat? HTTP/3 přináší spoustu nových konceptů, které nebyly v praxi vyzkoušeny a můžou přinést řadu nečekaných problémů. Například už teď víme, že přibližně 3 až 7 % všech pokusů o navázání spojení pomocí QUIC selže. To je poměrně velké číslo a klienti tak budou muset mít stále možnost přejít na záložní řešení v podobě HTTP/2, pokud se dostanou do této situace. Obvykle jde o problém v síti, která například zakazuje UDP provoz. To ovšem zároveň znamená, že se pro jednoho klienta může situace změnit – přenesete notebook z domova do práce a najednou QUIC nefunguje. Bude tedy muset existovat způsob, jakým zjistit, zda je v danou chvíli výhodnější použít TCP nebo UDP, a podle toho zvolit protokol.

QUIC je také výrazně náročnější na využití procesoru než jeho předchůdci. Na straně klientů to asi nebude představovat zásadní problém, ale na serveru vám při stejném toku vzrostou nároky na procesorový čas dvakrát až třikrát. To je opravdu hodně. To bude pravděpodobně pro provozovatele serverů největší překážka v implementaci HTTP/3. Z části za to může pravděpodobně fakt, že TCP a TLS jsou tu s námi velmi dlouho a máme optimalizované algoritmy, které mohou navíc část zátěže přenést na hardware. Tady ale měníme zásadně fungování protokolů, proto zatím tyto výhody nemáme. Pravděpodobně se to ale bude časem zlepšovat.

Další související problém spočívá v tom, že linuxový UDP stack je méně optimalizovaný než TCP stack. Nemuseli jsme to doposud příliš řešit, protože jsme UDP nikdy takovým způsobem a takto intenzivně nevyužívali. Teď se ukazuje, že TCP je na tom mnohem lépe než výrazně jednodušší UDP. Tady je také prostor pro výrazné zlepšení, potřebujeme dostat implementaci UDP na úroveň TCP.

Úplně nové TLS

Klasické TLS je protokol postavený nad TCP. Teď tu ale máme novou transportní vrstvu nad UDP – jak do ní implementujeme šifrování? TLS používá uvnitř dvě vrstvy: TLS records a TLS messages. Pracovní skupina vyvíjející standard se rozhodla, že vrstvu records už v novém protokolu nepotřebujeme a budou nám stačit holé TLS messages posílané pomocí QUIC. Žádná běžně používaná knihovna ale na něco takového nemá API. Podpora se připravuje v knihovně NSS od Mozilly a BoringSSL od Google, plus v některých méně rozšířených. Hodně rozšířená knihovna OpenSSL ale ještě vůbec s implementací nezačala. Vývojáři čekají na dokončení specifikace.

Jsme vlastně v podobné situaci, jaká tu byla s HTTP/2. Také trvalo velmi dlouho, než se podpora dostatečně rozšířila. Správci se ptali, jak něco takového mohou zapnout. Potřebovali rozšíření TLS zvané ALPN, které bylo jen v nových verzích OpenSSL. Celý svět ale ještě používal starší verze a trvalo dlouho, než se všechny komponenty postupně aktualizovaly. Byla to tehdy velká překážka, na které jsme dlouho stáli. Teď jsme v situaci, kdy OpenSSL ještě potřebný kód vůbec nemá. Ani se neblížíme stejnému bodu jako v případě rozšiřování HTTP/2. Ještě jsme ani nezačali.

Další implementační problém spočívá v tom, že všechny součásti QUIC leží v uživatelském prostoru, což znamená linkování nových knihoven k současným aplikacím a vznik nových problémů, které potřebují čas k doladění. QUIC také nemá žádné standardní API, což může do budoucna také znamenat problém. Pokud budete chtít ve své aplikaci QUIC použít, budete si muset nějaké API vybrat. Později už ale nebude snadné to měnit. Chybí také zatím podpora v mnoha nástrojích, například v těch pro sledování provozu – například WireShark. Pro TCP jsou ty nástroje velmi dlouho – vidíme v nich velikosti oken, čísla segmentů a další vlastnosti.

Kdy se dočkáme?

Současný plán hovoří o vydání standardu během července 2019. Nevím, jestli to vydrží, ale zatím je takový plán. To je ovšem jen termín vydání standardu. Kdy se ale dočkáme skutečně použitelných implementací?

Existuje více než tucet implementací protokolu QUIC, ale s HTTP/3 jsme na tom výrazně hůře. S HTTP/2 jsme na tom byli při vydání standardu lépe, existovala spousta implementací a mohli jsme je zkoušet. Tam ale zdaleka ještě nejsme. Apache ani Nginx s podporou ani nezačaly. Curl zatím také podporu nemá, ale doufám, že zhruba během měsíce se něco objeví. Zatím ale chybí podpora v knihovnách, takže to zřejmě bude problém slepice a vejce.

Stejně tak neexistuje zatím žádný prohlížeč, který by HTTP/3 implementoval. Bohužel nemám žádné zprávy o Firefoxu, ale Patrick McManus někde ukazoval vlastní Firefox s podporou HTTP/3. Pracuje na tom. Google už ale potvrdil, že v březnu vydá Chrome s podporou nového protokolu. Půjde pravděpodobně o nějakou vývojářskou verzi.

UX DAy - tip 2

Pohled do křišťálové koule

Daniel Stenberg na konci své přednášky zkusil předpovědět, jak to bude s rozšiřováním HTTP/3. Podle jeho slov bude ještě nějaký čas trvat, než se začne HTTP/3 nasazovat. Bude také růst pomaleji než HTTP/2, kvůli všem zmíněným problémům. Pravděpodobně tedy ještě nějakou dobu zůstaneme s HTTP/2. QUIC je ale rozhodně protokol budoucnosti. Je celkem jedno, kdy se objeví HTTP/3.

S vydáním standardu QUIC v létě to ale zdaleka neskončí, je tu spousta dalších výzev a potenciálních problémů, pro které se určitě bude hledat řešení pro další verzi specifikace: multipath, nespolehlivé toky, další aplikační protokoly a podobně. Určitě se během několika let dočkáme QUIC verze 2.

Byl pro vás článek přínosný?

Autor článku

Petr Krčmář pracuje jako šéfredaktor serveru Root.cz. Studoval počítače a média, takže je rozpolcen mezi dva obory. Snaží se dělat obojí, jak nejlépe umí.