Sono già passati più di 20 anni da quando visualizziamo pagine web tramite il protocollo HTTP. La maggior parte degli utenti non si è mai realmente interrogata su cosa sia e come funzioni. Altri sanno che sotto HTTP c'è TLS, e sotto di esso TCP, e a sua volta IP e così via. Ma ci sono anche degli eretici che considerano TCP un concetto obsoleto, desiderando qualcosa di più veloce, affidabile e sicuro. Tuttavia, nei loro tentativi di inventare un nuovo protocollo ideale, sono tornati alle tecnologie degli anni '80 e cercano di costruire su di esse il loro meraviglioso nuovo mondo.

Un po' di storia: HTTP/1.1
Nel 1997, il protocollo di scambio di informazioni testuali HTTP versione 1.1 ottenne il suo RFC. A quel tempo, il protocollo era già utilizzato dai browser da diversi anni e il nuovo standard è rimasto in vigore per altri quindici. Il protocollo funzionava esclusivamente secondo il principio richiesta-risposta e era principalmente destinato alla trasmissione di informazioni testuali.
HTTP è stato progettato per funzionare sopra il protocollo TCP, il quale garantisce la consegna affidabile dei pacchetti al destinatario. Il funzionamento di TCP si basa sull'instaurazione e il mantenimento di una connessione sicura tra i punti finali e sulla suddivisione del traffico in segmenti. I segmenti hanno un proprio numero sequenziale e un checksum. Se uno dei segmenti non arriva o arriva con un checksum errato, il trasferimento si interromperà finché non sarà recuperato il segmento mancante.
In HTTP/1.0, la connessione TCP veniva chiusa dopo ogni richiesta. Questo era estremamente dispendioso, poiché l'instaurazione di una connessione TCP (3-Way Handshake) non è un processo rapido. In HTTP/1.1 è stato introdotto il meccanismo keep-alive, che consente di riutilizzare una singola connessione per più richieste. Tuttavia, poiché questo può facilmente diventare un collo di bottiglia, in diverse implementazioni di HTTP/1.1 è consentita l'apertura di più connessioni TCP verso un singolo host. Ad esempio, in Chrome e nelle ultime versioni di Firefox, sono consentite fino a sei connessioni.

La crittografia era prevista anche per essere delegata ad altri protocolli, e a tale scopo, sopra TCP veniva utilizzato il protocollo TLS, che proteggeva i dati in modo piuttosto affidabile, ma aumentava ulteriormente il tempo necessario per stabilire una connessione. Alla fine, il processo di handshake è apparso in questo modo:

Illustrazione Cloudflare
Pertanto, HTTP/1.1 presentava una serie di problemi:
- Lentezza nell'instaurazione della connessione.
- I dati vengono trasmessi in formato testuale, il che rende inefficace la trasmissione di immagini, video e altre informazioni non testuali.
- Una connessione TCP è utilizzata per una sola richiesta, quindi le altre richieste devono trovare un'altra connessione oppure attendere che la richiesta attuale venga rilasciata.
- È supportato solo il modello pull. Nello standard non è presente nulla riguardo al server-push.
- Le intestazioni vengono trasmesse in testo.
Se il server-push viene implementato in qualche modo tramite il protocollo WebSocket, le altre problematiche devono essere affrontate in modo più radicale.
Un po' di modernità: HTTP/2
Nel 2012, nelle profondità di Google, è iniziato il lavoro sul protocollo SPDY (pronunciato 'speedy'). Il protocollo doveva risolvere i principali problemi di HTTP/1.1 e mantenere al contempo la compatibilità retroattiva. Nel 2015, il gruppo di lavoro IETF ha presentato la specifica HTTP/2, basata sul protocollo SPDY. Ecco quali sono state le differenze in HTTP/2:
- Serializzazione binaria.
- Multiplexing di più richieste HTTP in una singola connessione TCP.
- Server-push integrato (senza WebSocket).
Il protocollo ha rappresentato un grande passo avanti. È sicuramente e non richiede la creazione di più connessioni TCP: tutte le richieste verso un unico host vengono multiplexate in una sola. Quindi, in una connessione ci sono diversi stream, ognuno dei quali ha il proprio ID. Un ulteriore vantaggio è l'inclusione di server-push.
Tuttavia, il multiplexing porta a un'altra problematica fondamentale. Immagina di eseguire 5 richieste a un singolo server in modo asincrono. Utilizzando HTTP/2, tutte queste richieste verranno elaborate attraverso una sola connessione TCP, il che significa che se uno dei segmenti di qualsiasi richiesta viene perso o arriva in modo errato, la trasmissione di tutte le richieste e risposte si interromperà finché il segmento mancante non sarà recuperato. È evidente che peggiorando la qualità della connessione, più lentamente funziona HTTP/2. , nelle condizioni in cui i pacchetti persi costituiscono il 2% del totale, HTTP/1.1 si comporta meglio su un browser rispetto a HTTP/2, poiché apre 6 connessioni anziché una sola.
Questo problema è noto come 'head-of-line blocking' e, sfortunatamente, non è possibile risolverlo attraverso l'uso di TCP.

Illustrazione Daniel Steinberg
Come risultato, gli sviluppatori dello standard HTTP/2 hanno fatto un enorme lavoro e hanno realizzato praticamente tutto ciò che era possibile fare a livello applicativo del modello OSI. È giunto il momento di scendere al livello di trasporto e inventare un nuovo protocollo di trasporto.
Abbiamo bisogno di un nuovo protocollo: UDP vs TCP
È diventato rapidamente chiaro che implementare un protocollo di trasporto completamente nuovo è una sfida impossibile nelle attuali circostanze. Infatti, le apparecchiature o i middle-box (router, firewall, server NAT…) conoscono il livello di trasporto, e insegnare loro qualcosa di nuovo è un compito estremamente difficile. Inoltre, il supporto dei protocolli di trasporto è integrato nel nucleo dei sistemi operativi, e anche i nuclei non cambiano con molta volontà.
A questo punto si potrebbe gettare la spugna e dire: «Certo, inventeremo il nuovo HTTP/3 con il briscola e le cortigiane, ma ci vorranno 10-15 anni prima di vederlo implementato (circa il tempo necessario perché la maggior parte della hardware venga sostituita)», ma c'è un'altra opzione meno ovvia: utilizzare il protocollo UDP. Sì, proprio quel protocollo con cui negli anni '90 e all'inizio del 2000 ci scambiavamo file nella rete locale. Praticamente tutte le apparecchiature di oggi sanno lavorare con esso.
Quali sono i vantaggi dell'UDP rispetto al TCP? In primo luogo, non abbiamo una sessione di livello di trasporto di cui l'hardware è a conoscenza. Questo ci permette di definire noi stessi la sessione sui punti finali e di gestire i conflitti che sorgono. Quindi non siamo limitati a una o più sessioni (come nel TCP), ma possiamo crearne quante ne abbiamo bisogno. In secondo luogo, la trasmissione dei dati tramite UDP avviene più rapidamente rispetto al TCP. Così, in teoria, possiamo superare il limite di velocità attuale raggiunto con HTTP/2.
Tuttavia, l'UDP non garantisce l'affidabilità della trasmissione dei dati. In pratica, inviamo semplicemente i pacchetti, sperando che vengano ricevuti dall'altra parte. Non sono stati ricevuti? Beh, non è andata bene… Questo era abbastanza per la trasmissione di video per adulti, ma per cose più serie è necessaria affidabilità, il che implica dover sovrapporre qualcos'altro all'UDP.
Come nel caso di HTTP/2, il lavoro per la creazione di un nuovo protocollo è iniziato in Google nel 2012, cioè all'incirca nello stesso periodo in cui ha avuto inizio il lavoro su SPDY. Nel 2013, Jim Roskind ha presentato il protocollo al pubblico. , e già nel 2015 è stata presentata una bozza di Internet per la standardizzazione all'IETF. Già a quel tempo, il protocollo sviluppato da Roskind in Google differiva notevolmente da quello proposto per la standardizzazione, quindi la versione di Google è stata chiamata gQUIC.
Che cos'è QUIC
In primo luogo, come già detto, è un'interfaccia sopra UDP. Sopra UDP viene stabilita una connessione QUIC, in cui, analogamente a HTTP/2, possono esistere più stream. Questi stream esistono solo ai punti finali e sono gestiti in modo indipendente. Se si verifica la perdita di un pacchetto in uno stream, gli altri non ne saranno toccati.

Illustrazione Daniel Steinberg
In secondo luogo, la crittografia ora è realizzata non come un livello separato, ma è inclusa nel protocollo. Questo consente di creare una connessione e scambiare chiavi pubbliche con un solo handshake, oltre a consentire di utilizzare il meccanismo 0-RTT handshake e in generale evitare ritardi durante l'handshake. Inoltre, ora è possibile crittografare pacchetti di dati singoli. Ciò consente di non attendere il completamento della ricezione dei dati dallo stream, ma di decifrare i pacchetti ricevuti in modo indipendente. Tale modalità operativa era praticamente impossibile in TCP, poiché TLS e TCP operavano separatamente l'uno dall'altro e TLS non poteva sapere in quali parti TCP avrebbe spezzato i dati. Di conseguenza, non poteva preparare i suoi segmenti in modo che si adattassero ai segmenti TCP uno a uno e potessero essere decifrati in modo indipendente. Tutti questi miglioramenti consentono a QUIC di ridurre la latenza rispetto a TCP.

In terzo luogo, il concetto di stream leggeri consente di scollegare la connessione dall'indirizzo IP del client. Questo è importante, ad esempio, quando il client passa da un punto di accesso Wi-Fi a un altro, cambiando il proprio IP. In questo caso, utilizzando TCP, si verifica un lungo processo durante il quale le connessioni TCP esistenti scadono e vengono create nuove connessioni con il nuovo IP. Nel caso di QUIC, il client continua semplicemente a inviare pacchetti al server con il nuovo IP mantenendo il vecchio ID dello stream. Poiché ora l'ID dello stream è unico e non viene riutilizzato, il server comprende che il client ha cambiato IP, reinvia i pacchetti persi e continua la comunicazione al nuovo indirizzo.
In quarto luogo, QUIC viene implementato a livello di applicazione, e non del sistema operativo. Questo, da un lato, consente di apportare modifiche al protocollo più velocemente, poiché, per ottenere un aggiornamento, basta semplicemente aggiornare la libreria, senza dover attendere una nuova versione del SO. Dall'altro lato, ciò comporta un forte aumento del consumo di CPU.
E infine, le intestazioni. La compressione delle intestazioni è uno dei punti che differiscono tra QUIC e gQUIC. Non vedo il senso di dedicare molto tempo a questo, dico solo che nella versione presentata per la standardizzazione, la compressione delle intestazioni è stata resa il più simile possibile a quella delle intestazioni in HTTP/2. Per saperne di più, si può leggere .
Quanto è più veloce?
È una domanda complessa. Il fatto è che finché non abbiamo uno standard, non c'è molto da misurare. Probabilmente, i unici dati statistici di cui disponiamo sono le statistiche di Google, che utilizza gQUIC dal 2013 e nel 2016 , che circa il 90% del traffico verso i loro server da Chrome utilizza ora QUIC. Nella stessa presentazione riportano che tramite gQUIC le pagine si caricano circa il 5% più velocemente, mentre nei video in streaming ci sono il 30% di meno di blocchi rispetto a TCP.
Nel 2017, un gruppo di ricercatori guidato da Arash Molavi Kakhki ha pubblicato uno studio sulle prestazioni di gQUIC rispetto a TCP.
Lo studio ha rivelato alcuni punti deboli di gQUIC, come l'instabilità nel mescolare pacchetti di rete, l'avidità (ingiustizia) per la larghezza di banda e la trasmissione più lenta di piccoli oggetti (fino a 10 kB). Quest'ultima, tuttavia, riesce a essere compensata utilizzando 0-RTT. In tutti gli altri casi esaminati, gQUIC ha mostrato un aumento della velocità rispetto a TCP. Parlare di cifre specifiche è complicato. È meglio leggere o .
Qui bisogna dire che questi dati riguardano specificamente gQUIC e non sono attuali per lo standard in fase di sviluppo. Cosa accadrà con QUIC: resta un mistero, ma c'è speranza che i punti deboli identificati in gQUIC vengano presi in considerazione e corretti.
Un po' di futuro: e per HTTP/3?
Ecco, qui tutto è cristallino: l'API non cambierà. Rimarrà esattamente come era in HTTP/2. E se l'API rimane invariata, la transizione a HTTP/3 dovrà avvenire utilizzando una versione aggiornata della libreria sul backend, che supporta il trasporto tramite QUIC. Purtroppo, ci vorrà ancora molto tempo prima di poter eliminare il fall-back alle vecchie versioni di HTTP, poiché internet non è ancora pronta per una transizione completa a UDP.
Chi supporta già
Ecco le implementazioni esistenti di QUIC. Nonostante l'assenza di uno standard, l'elenco non è male.
Nessun browser attualmente supporta QUIC in una release stabile. Recentemente si è saputo che in Chrome è stata attivata la supporto per HTTP/3, ma per ora solo in Canary.
Tra i backend, HTTP/3 è supportato solo da e , ma attualmente in modo sperimentale. NGINX alla fine della primavera del 2019 , ha comunicato di aver iniziato a lavorare sul supporto per HTTP/3, ma non hanno ancora completato.
Quali problemi ci sono
Viviamo in un mondo reale, dove nessuna grande tecnologia può diffondersi senza incontrare resistenza, e QUIC non fa eccezione.
La cosa più importante è che bisogna spiegare al browser che "https://" non porta necessariamente al porto TCP 443. Potrebbe non esserci affatto TCP. A questo scopo si utilizza l'intestazione Alt-Svc. Essa consente di comunicare al browser che questo sito web è accessibile anche attraverso un certo protocollo ed un certo indirizzo. In teoria dovrebbe funzionare come un orologio, ma nella pratica ci imbattemmo nel fatto che UDP potrebbe, ad esempio, essere bloccato da un firewall per prevenire attacchi DDoS.
Ma anche se UDP non è bloccato, il client potrebbe trovarsi dietro un router NAT, impostato per mantenere la sessione TCP tramite l'indirizzo IP, e poiché utilizziamo UDP, dove non c'è una sessione hardware, il NAT non manterrà la connessione, e la sessione QUIC .
Tutti questi problemi derivano dal fatto che l'UDP non è stato precedentemente utilizzato per la trasmissione di contenuti internet, e i produttori di hardware non potevano prevedere che ciò sarebbe accaduto un giorno. Allo stesso modo, gli amministratori attualmente non comprendono bene come configurare le loro reti per il funzionamento di QUIC. Questa situazione cambierà lentamente, e, in ogni caso, tali cambiamenti richiederanno meno tempo rispetto all'implementazione di un nuovo protocollo di livello di trasporto.
Inoltre, come già descritto, QUIC aumenta notevolmente l'uso della CPU. Daniel Stenberg un incremento dell'uso della CPU fino a tre volte.
Quando arriverà HTTP/3
Standard Entro maggio 2020, ma considerando che attualmente i documenti pianificati per luglio 2019 non sono ancora completati, si può dire che la data verrà probabilmente posticipata.
Google utilizza la propria implementazione di gQUIC dal 2013. Se si guarda alla richiesta HTTP inviata al motore di ricerca di Google, si può vedere questo:

Conclusioni
QUIC al momento appare come una tecnologia piuttosto grezza, ma estremamente promettente. Considerando che negli ultimi 20 anni tutte le ottimizzazioni dei protocolli di livello di trasporto si sono concentrate principalmente su TCP, QUIC, che nella maggior parte dei casi offre migliori prestazioni, appare già ora molto bene.
Tuttavia, ci sono ancora problemi irrisolti che dovranno essere affrontati nei prossimi anni. Il processo potrebbe allungarsi a causa dell'hardware coinvolto, che nessuno ama aggiornare, ma nonostante ciò tutti i problemi sembrano piuttosto risolvibili e prima o poi avremo HTTP/3.
Il futuro è dietro l'angolo!
Fonte: habr.com
