Het is uiterst boeiend om het QUIC-protocol te observeren, en daarom schrijven we er graag over. Terwijl eerdere publicaties over QUIC meer een historische (of regionaal informatieve, als u wilt) achtergrond en technische details hadden, zijn we vandaag blij een vertaling van een ander soort te publiceren ā we gaan het hebben over het daadwerkelijke gebruik van het protocol in 2019. Dit betreft niet een kleine infrastructuur die vanuit een garage opereert, maar Uber, dat bijna wereldwijd actief is. Hoe de ingenieurs van het bedrijf tot de beslissing kwamen om QUIC in productie te gebruiken, hoe ze testen uitvoerden en wat ze na de uitrol in productie zagen ā dat leest u hieronder.
Afbeeldingen zijn klikbaar. Veel leesplezier!
Uber is wereldwijd aanwezig in maar liefst 600 steden, waarbij de app volledig afhankelijk is van draadloos internet van meer dan 4500 mobiele netwerkoperators. Gebruikers verwachten dat de app niet alleen snel werkt, maar realtime ā om dit te waarborgen, heeft de Uber-app lage latenties en een zeer betrouwbare verbinding nodig. Helaas voelt de stack zich niet goed in dynamische en verliesgevoelige draadloze netwerken. We hebben geleerd dat in dit geval de lage prestaties direct gerelateerd zijn aan de implementaties van TCP in de kernel van besturingssystemen.
Om het probleem op te lossen, hebben we , een modern protocol met kanaalmultiplexing toegepast, dat ons meer controle geeft over de prestaties van het transportprotocol. Op dit moment standaardiseert de werkgroep QUIC als .
Na gedetailleerde tests zijn we tot de conclusie gekomen dat het implementeren van QUIC in onze app de 'tail' latenties verlaagd in vergelijking met TCP. We hebben een vermindering van 10-30% waargenomen voor HTTPS-verkeer, zowel voor de chauffeurs- als passagiersapp. Bovendien gaf QUIC ons end-to-end controle over de gebruikerspakketten.
In dit artikel delen we onze ervaring met het optimaliseren van TCP voor Uber-applicaties met behulp van een stack die QUIC ondersteunt.
Het laatste woord in technologie: TCP
Vandaag is TCP het meest gebruikte transportprotocol voor het afleveren van HTTPS-verkeer op het internet. TCP zorgt voor een betrouwbare byte-stroom, waardoor het omgaat met netwerkoverbelasting en verliezen op het kanaalniveau. Het wijdverspreide gebruik van TCP voor HTTPS-verkeer kan worden verklaard door de alomtegenwoordigheid van het protocol (bijna elk besturingssysteem bevat TCP), de beschikbaarheid op het grootste deel van de infrastructuur (zoals load balancers, HTTPS-proxies en CDN's) en de 'out-of-the-box' functionaliteit die bijna op de meeste platforms en netwerken beschikbaar is.
De meeste gebruikers maken onze applicatie onderweg gebruik van, en de 'tail' vertragingen van TCP waren ver verwijderd van de eisen van ons real-time HTTPS-verkeer. Simpel gezegd, gebruikers wereldwijd ondervonden dit ā Figuur 1 toont de vertragingen in grote steden:
Figuur 1. De omvang van 'tail' vertragingen varieert in de belangrijkste steden waar Uber aanwezig is.
Hoewel de vertragingen in de Indiase en Braziliaanse netwerken groter waren dan in de VS en het VK, zijn de tail-vertragingen aanzienlijk groter dan de gemiddelde vertragingen. En dit is zelfs het geval voor de VS en het VK.
TCP-prestaties via de lucht
TCP is ontworpen voor bedrade netwerken, dat wil zeggen met een focus op goed voorspelbare verbindingen. Echter, bij draadloze netwerken bestaan er eigen kenmerken en moeilijkheden. Ten eerste zijn draadloze netwerken gevoelig voor verliezen door interferentie en signaalverzwakking. Bijvoorbeeld, Wi-Fi netwerken zijn gevoelig voor microgolven, bluetooth en andere radiogolven. Mobiele netwerken lijden onder signaalverlies () door reflectie/absorptie van het signaal door objecten en gebouwen, evenals door van naburige Dit leidt tot aanzienlijkere (4-10 keer) en variabele en pakketverliezen in vergelijking met een bedrade verbinding.
Om fluctuaties in de bandbreedte en verliezen te bestrijden, gebruiken mobiele netwerken doorgaans grote buffers voor verkeerspieken. Dit kan leiden tot overmatige buffering, wat betekent dat er grotere vertragingen optreden. Vaak beschouwt TCP dergelijke buffering als verlies vanwege een verhoogde time-out, waardoor TCP geneigd is om opnieuw te verzenden en zo de buffer vult. Dit probleem staat bekend als (), en dit is een zeer de moderne internet.
De prestaties van mobiele netwerken variëren afhankelijk van de provider, de regio en het tijdstip. In Figuur 2 hebben we de mediane HTTPS-vertragingen van celnetwerken binnen een bereik van 2 kilometer verzameld. Gegevens zijn verzameld voor de twee grootste mobiele aanbieders in Delhi, India. Zoals we kunnen zien, varieert de prestatie van cel naar cel. Ook verschillen de prestaties van de ene provider van die van de andere. Dit wordt beïnvloed door factoren zoals de toegangspatronen tot het netwerk, rekening houdend met tijd en locatie, de mobiliteit van gebruikers, en de netwerkinfrastructuur, rekening houdend met de dichtheid van torens en de verhouding van netwerktype (LTE, 3G, enz.).
Figuur 2. Vertragingen binnen een straal van 2 kilometer. Delhi, India.
Ook de prestaties van mobiele netwerken fluctueren in de tijd. In Figuur 3 wordt de mediane vertraging gedurende de weekdagen weergegeven. We hebben ook verschillen op een kleinere schaal waargenomen ā binnen ƩƩn dag en uur.
Figuur 3. Staartvertragingen kunnen aanzienlijk variƫren op verschillende dagen, maar binnen dezelfde provider.
Al het bovenstaande leidt ertoe dat de TCP-prestaties inefficiƫnt zijn in draadloze netwerken. Voordat we echter naar alternatieven voor TCP zoeken, willen we een nauwkeurig begrip ontwikkelen van de volgende punten:
- is TCP de voornaamste oorzaak van staartvertragingen in onze applicaties?
- hebben moderne netwerken significante en uiteenlopende round-trip vertragingen (RTT)?
- wat is het effect van RTT en verlies op de prestaties van TCP?
Analyseren van de TCP-prestaties
Om te begrijpen hoe we de prestaties van TCP hebben geanalyseerd, laten we kort herinneren aan hoe TCP gegevens van de verzender naar de ontvanger verzendt. Eerst stelt de verzender een TCP-verbinding tot stand door middel van een drievoudige : de verzender verzendt een SYN-pakket, wacht op een SYN-ACK-pakket van de ontvanger en verzendt dan een ACK-pakket. De extra tweede en derde rondes zijn nodig voor het tot stand brengen van de TCP-verbinding. De ontvanger bevestigt de ontvangst van elk pakket (ACK) om een betrouwbare aflevering te garanderen.
Als een pakket of ACK verloren gaat, retransmitteert de verzender na een time-out (RTO, ). RTO wordt dynamisch berekend, gebaseerd op verschillende factoren, zoals de verwachte vertraging in RTT tussen de verzender en de ontvanger.
Figuur 4. Pakketuitwisseling via TCP/TLS omvat retransmittmechanismen.
Om te bepalen hoe TCP in onze applicaties functioneerde, volgden we TCP-pakketten met behulp van gedurende een week op live verkeer van Indiase grensservers. Daarna analyseerden we de TCP-verbindingen met behulp van . Daarnaast ontwikkelden we een Android-app die gesimuleerd verkeer naar een testserver stuurt, wat zoveel mogelijk lijkt op echt verkeer. Smartphones met deze app werden uitgedeeld aan verschillende medewerkers, die logboeken verzamelden gedurende enkele dagen.
De resultaten van beide experimenten waren consistent met elkaar. We zagen hoge RTT-latenties; de staartwaarden waren bijna 6 keer hoger dan de mediaan; de gemiddelde latentie was meer dan 1 seconde. Veel verbindingen hadden pakketverlies, wat TCP dwong om 3,5% van alle pakketten te retransmitteren. In gebieden met overbelasting, zoals luchthavens en treinstations, observeerden we 7% verlies. Deze resultaten zetten vraagtekens bij de gangbare opvatting dat de in mobiele netwerken gebruikte de verliezen op transportniveau aanzienlijk verminderen. Hieronder staan de testresultaten van de āsimulatorā-app:
Netwerkmatrices
Waarden
RTT, milliseconden [50%, 75%, 95%, 99%]
[350, 425, 725, 2300]
RTT-variantie, seconden
Gemiddeld ~1,2 s
Pakketverlies in onbetrouwbare verbindingen
Gemiddeld ~3,5% (7% in overbelaste gebieden)
Bijna de helft van deze verbindingen had ten minste ƩƩn pakketverlies, voornamelijk SYN- en SYN-ACK-pakketten. De meeste TCP-implementaties gebruiken een RTO-waarde van 1 seconde voor SYN-pakketten, die exponentieel toeneemt bij daaropvolgende verliezen. De laadtijd van de applicatie kan toenemen doordat TCP meer tijd nodig heeft om verbindingen tot stand te brengen.
In het geval van datapakketten verminderen hoge RTO-waarden de nuttige netwerkutilisatie aanzienlijk bij tijdelijke verliezen in draadloze netwerken. We ontdekten dat de gemiddelde retransmittijd ongeveer 1 seconde was, met een staartvertraging van bijna 30 seconden. Deze hoge latenties op het TCP-niveau veroorzaakten HTTPS-timeouts en herhaalde aanvragen, wat de vertraging en inefficiƫntie van het netwerk verder vergrootte.
Terwijl het 75e percentiel van de gemeten RTT rond de 425 ms was, was het 75e percentiel voor TCP bijna 3 seconden. Dit suggereert dat verliezen ervoor zorgden dat TCP 7-10 keer moest doorlopen om gegevens succesvol te verzenden. Dit kan het gevolg zijn van een ineffectieve berekening van RTO en het onvermogen van TCP om snel op verlies te reageren. in het venster en de ineffectiviteit van het congestiebeheersalgoritme, dat geen verschil maakt tussen draadloze verliezen en verliezen door netwerkcongestie. Hieronder staan de testresultaten van TCP-verliezen:
Statistieken van TCP-verliezen
Waarde
Percentage verbindingen met ten minste 1 verliespakket
45%
Percentage verbindingen met verliezen tijdens het opzetten van de verbinding
30%
Percentage verbindingen met verliezen tijdens gegevensuitwisseling
76%
Vertragingen in retransmissie, seconden [50%, 75%, 95%, 99%]
[1, 2.8, 15, 28]
Verdeling van het aantal retransmissies voor ƩƩn pakket of TCP-segment
[1,3,6,7]
Toepassing van QUIC
Aanvankelijk ontworpen door Google, QUIC is een moderne multi-threaded transportprotocol dat bovenop UDP opereert. Op dit moment bevindt QUIC zich in (we hebben al geschreven dat er als het ware twee versies van QUIC zijn; geĆÆnteresseerden ā opmerking van de vertaler). Zoals weergegeven in Figuur 5, bevindt QUIC zich onder HTTP/3 (in feite is HTTP/2 bovenop QUIC HTTP/3, dat momenteel sterk genormaliseerd wordt). Het vervangt gedeeltelijk de HTTPS- en TCP-niveaus door UDP te gebruiken voor het vormen van pakketten. QUIC ondersteunt alleen veilige gegevensoverdracht, aangezien TLS volledig in QUIC is ingebouwd.

Figuur 5: QUIC opereert onder HTTP/3 en vervangt TLS, dat eerder onder HTTP/2 werkte.
Hieronder geven we de redenen aan die ons overtuigden om QUIC te gebruiken voor een versterking van TCP:
- 0-RTT verbinding opzetten. QUIC maakt hergebruik van autorisaties uit eerdere verbindingen mogelijk, waardoor het aantal veiligheids-handshakes wordt verminderd. In de toekomst 0-RTT ondersteunen, maar de drieledige TCP-handshake blijft nog steeds verplicht.
- overwinning van HoL-blokkering. HTTP/2 gebruikt ƩƩn TCP-verbinding voor elke client om prestaties te verbeteren, maar dit kan leiden tot HoL (head-of-line) blokkering. QUIC vereenvoudigt multiplexing en levert aanvragen onafhankelijk van elkaar aan de applicatie.
- congestiebeheer. QUIC bevindt zich op de applicatielaag, waardoor het gemakkelijker wordt om het hoofdtransportalgoritme bij te werken dat het verzenden beheert op basis van netwerkomstandigheden (verliespercentage of RTT). De meeste TCP-implementaties maken gebruik van het algoritme , dat niet optimaal is voor latency-gevoelige verkeersstromen. Recent ontwikkelde algoritmes zoals , modelleren het netwerk nauwkeuriger en optimaliseren de vertragingen. QUIC maakt gebruik van BBR en kan dit algoritme bijwerken naarmate het .
- voor het aanvullen van verlies. QUIC activeert twee TLP () voordat de RTO in werking treedt ā zelfs wanneer verliezen zeer merkbaar zijn. Dit verschilt van TCP-implementaties. TLP retransmitteert voornamelijk het laatste pakket (of een nieuw, indien beschikbaar) om een snelle aanvulling te starten. Het omgaan met tail latencies is bijzonder nuttig voor hoe Uber met het netwerk omgaat, vooral voor korte, episodische en latency-gevoelige gegevensoverdrachten.
- geoptimaliseerde ACK. Aangezien elk pakket een uniek volgnummer heeft, is er geen probleem van pakketten tijdens hun retransmissie. ACK-pakketten bevatten ook tijd voor de verwerking van het pakket en de generatie van ACK aan de klantzijde. Deze kenmerken zorgen ervoor dat QUIC RTT nauwkeuriger berekent. ACK in QUIC ondersteunt tot 256 gebieden , wat de verzender helpt om beter om te gaan met het herschikken van pakketten en minder bytes in het proces te gebruiken. Selectieve ACK () in TCP lost dit probleem niet in alle gevallen op.
- verbinding migratie. QUIC-verbindingen worden geĆÆdentificeerd met behulp van een 64-bits ID, zodat als de klant IP-adressen verandert, het ID van de oude verbinding op het nieuwe IP-adres kan worden gebruikt, zonder onderbrekingen. Dit is een veel voorkomende praktijk voor mobiele applicaties wanneer de gebruiker tussen Wi-Fi en mobiele verbindingen schakelt.
Alternatieven voor QUIC
We hebben alternatieve benaderingen overwogen om het probleem op te lossen voordat we voor QUIC kozen.
Ten eerste hebben we geprobeerd TPC PoPs (Points of Presence) te implementeren om TCP-verbindingen dichter bij de gebruikers te beƫindigen. In feite beƫindigt een PoP de TCP-verbinding met een mobiel apparaat dichter bij het mobiele netwerk en proxy't het verkeer naar de oorspronkelijke infrastructuur. Door TCP dichterbij te beƫindigen, kunnen we mogelijk de RTT verminderen en er zeker van zijn dat TCP actiever reageert op de dynamische draadloze omgeving. Onze experimenten toonden echter aan dat het grootste deel van de RTT en verliezen afkomstig is van mobiele netwerken en dat het gebruik van PoPs geen significante prestatieverbetering biedt.
We hebben ook gekeken naar het afstemmen van TCP-parameters. Het configureren van de TCP-stack op onze heterogene randservers was moeilijk, omdat TCP inconsistente implementaties heeft in verschillende besturingssystemen. Het was uitdagend om dit te implementeren en verschillende netwerkconfiguraties te testen. Directe aanpassing van TCP op mobiele apparaten was onmogelijk vanwege gebrek aan bevoegdheid. Nog belangrijker is dat functies zoals 0-RTT-verbindingen en verbeterde RTT-voorspelling cruciaal zijn voor de architectuur van het protocol, waardoor het niet mogelijk is om aanzienlijke voordelen te behalen door alleen TCP aan te passen.
Ten slotte hebben we verschillende op UDP gebaseerde protocollen geĆ«valueerd die problemen bij videostreaming verhelpen ā we wilden weten of deze protocollen nuttig zouden zijn in ons geval. Helaas ontbrak het aan veel beveiligingsinstellingen en vereiste het een extra TCP-verbinding voor metadata en besturingsinformatie.
Onze bevindingen toonden aan dat QUIC nauwelijks het enige protocol is dat kan helpen met het probleem van internetverkeer, terwijl zowel veiligheid als prestaties in overweging worden genomen.
Integratie van QUIC in het platform
Om QUIC succesvol te integreren en de prestaties van de applicatie onder slechte verbindingen te verbeteren, hebben we de oude stack (HTTP/2 boven TLS/TCP) vervangen door het QUIC-protocol. We hebben de netwerklibrary uit , die de originele, Google-versie van het protocol ā gQUIC ā bevat. Deze implementatie wordt ook voortdurend verbeterd om de laatste specificatie van de IETF te volgen.
Eerst hebben we Cronet geĆÆntegreerd in onze Android-applicaties om ondersteuning voor QUIC toe te voegen. De integratie is zo uitgevoerd dat de migratiekosten tot een minimum worden beperkt. In plaats van de oude netwerklayer volledig te vervangen, die gebruik maakte van de library , hebben we Cronet geĆÆntegreerd ONDER de OkHttp API-framework. Door de integratie op deze manier uit te voeren, hebben we wijzigingen in onze netwerkoproepen (die gebruik maken van ) op API-niveau vermeden.
Net als bij de aanpak voor Android-apparaten hebben we Cronet geĆÆmplementeerd in de Uber-apps voor iOS, waarbij we HTTP-verkeer onderscheppen vanuit de netwerken , met gebruik van . Deze abstractie, geboden door de iOS Foundation, verwerkt protocol-specifieke URL-gegevens en zorgt ervoor dat we Cronet in onze iOS-applicaties kunnen integreren zonder aanzienlijke migratiekosten.
Beƫindiging van QUIC op Google Cloud-loadbalancers
Aan de backend wordt de beƫindiging van QUIC verzorgd door de Google Cloud Load balancing-infrastructuur, die gebruik maakt van Headers in responses to support QUIC. In general, the load balancer adds an alt-svc header to each HTTP request, and it validates QUIC support for the domain. When the Cronet client receives an HTTP response with such a header, it uses QUIC for subsequent HTTP requests to that domain. Once the load balancer completes QUIC, our infrastructure explicitly sends this action over HTTP2/TCP to our data centers.
Prestaties: resultaten
De uitgegeven prestaties zijn de belangrijkste reden voor onze zoektocht naar het beste protocol. Om te beginnen hebben we een opstelling gecreƫerd met , om te achterhalen hoe QUIC zich gedraagt bij verschillende netwerkprofielen. Om de werking van QUIC in echte netwerken te controleren, hebben we experimenten uitgevoerd terwijl we door New Delhi reden, waarbij we gebruik maakten van geƫmuleerd netwerkverkeer dat sterk leek op HTTP-aanroepen in een passagiersapplicatie.
Experiment 1
Informatie voor het experiment:
- testapparaten op Android met de OkHttp- en Cronet-stacks, om ervoor te zorgen dat we HTTPS-verkeer via TCP en QUIC doorsturen;
- een Java-gebaseerde emulatieterver, die uniforme HTTPS-headers in de antwoorden verzendt en de clientapparaten belast om verzoeken van hen te ontvangen;
- cloudproxies, die fysiek dichtbij India zijn geplaatst om TCP- en QUIC-verbindingen te beƫindigen. Terwijl we voor de beƫindiging van TCP een reverse proxy gebruikten op , was het moeilijk om een open-source reverse proxy voor QUIC te vinden. We hebben zelf een reverse proxy voor QUIC opgebouwd, gebruik makend van de basis QUIC-stack uit Chromium en verpakt als open-source in Chromium.
Figuur 6. De testopstelling voor TCP versus QUIC bestond uit Android-apparaten met OkHttp en Cronet, cloudproxies voor beƫindiging van verbindingen en een emulatieterver.
Experiment 2
Toen Google QUIC beschikbaar stelde via , gebruikten we dezelfde uitrusting, maar met ƩƩn wijziging: in plaats van NGINX gebruikten we Google's load balancers voor de beƫindiging van TCP- en QUIC-verbindingen van de apparaten en ook voor het routeren van HTTPS-verkeer naar de emulatieterver. De load balancers zijn wereldwijd verspreid, maar maken gebruik van de dichtstbijzijnde PoP-server (dankzij geolocatie).
Figuur 7. In het tweede experiment wilden we de latentie van de beƫindiging van TCP en QUIC vergelijken: met Google Cloud en met onze cloudproxy.
Uiteindelijk stonden ons een paar onthullingen te wachten:
- de beƫindiging via PoP verbeterde de prestaties van TCP. Aangezien load balancers TCP-verbindingen dichter bij gebruikers beƫindigen en uitstekend zijn geoptimaliseerd, resulteert dit in lagere RTT, wat de TCP-prestaties verbetert. En hoewel de impact op QUIC minder was, overtrof het TCP nog steeds in het verminderen van staartvertragingen (met 10-30 procent).
- zijn beĆÆnvloed door staarten . Hoewel onze QUIC-proxy verder van de apparaten was (met een vertraging van ongeveer 50 ms hoger) dan Google's load balancers, vertoonde het een vergelijkbare prestatie ā een daling van 15% in vertragingen versus 20% in de 99e percentiel bij TCP. Dit geeft aan dat de overgang op de laatste mijl een knelpunt (bottleneck) in het netwerk is.
Figuur 8. De resultaten van de twee experimenten tonen aan dat QUIC TCP aanzienlijk overtreft.
Veldverkeer
GeĆÆnspireerd door de experimenten hebben we ondersteuning voor QUIC geĆÆmplementeerd in onze Android- en iOS-applicaties. We hebben A/B-tests uitgevoerd om de impact van QUIC in de steden waar Uber aanwezig is te bepalen. Over het geheel genomen zagen we een significante vermindering van de staartvertragingen in zowel regio's als telecomoperators en netwerktypen.
De grafieken hieronder tonen procentuele verbeteringen van staarten (95e en 99e percentielen) per macroregio en verschillende netwerktypen ā LTE, 3G, 2G.
Figuur 9. In de testcases overtrof QUIC TCP qua vertragingen.
Vooruitgang
Dit lijkt pas het begin te zijn ā de uitrol van QUIC in productie heeft geweldige mogelijkheden geboden om de prestaties van applicaties in zowel stabiele als onbetrouwbare netwerken te verbeteren, namelijk:
Verhoogde dekking
Door de prestaties van het protocol op echt verkeer te analyseren, hebben we gezien dat ongeveer 80% van de sessies succesvol QUIC gebruikte voor van alle verzoeken, terwijl 15% van de sessies een combinatie van QUIC en TCP gebruikte. We vermoeden dat deze combinatie is ontstaan omdat de Cronet-bibliotheek terugschakelt naar TCP bij time-outs, aangezien het geen onderscheid kan maken tussen echte UDP-fouten en slechte netwerkcondities. Momenteel zoeken we naar een oplossing voor dit probleem, terwijl we werken aan de volgende implementatie van QUIC.
Optimalisatie van QUIC
Verkeer vanuit mobiele apps is gevoelig voor vertragingen, maar niet voor bandbreedte. Bovendien worden onze apps voornamelijk in mobiele netwerken gebruikt. Op basis van experimenten blijven de staartvertragingen hoog, zelfs met het gebruik van proxy's voor het beƫindigen van TCP en QUIC dicht bij de gebruikers. We zijn actief op zoek naar manieren om het congestiebeheer te verbeteren en de efficiƫntie van QUIC-verliesherstelalgoritmen te verhogen.
Met deze en enkele andere verbeteringen plannen we de gebruikerservaring te verbeteren, ongeacht het netwerk of de regio, door een gebruiksvriendelijker en naadloos pakkettransport wereldwijd toegankelijker te maken.
Bron: habr.com
