QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen

QUIC-protokollen er ekstremt interessant å se, og det er derfor vi elsker å skrive om den. Men hvis tidligere publikasjoner om QUIC var mer av en historisk (lokalhistorie, hvis du vil) natur og maskinvare, publiserer vi i dag en oversettelse av en annen type - vi vil snakke om den virkelige anvendelsen av protokollen i 2019. Dessuten snakker vi ikke om liten infrastruktur basert i en såkalt garasje, men om Uber, som opererer nesten over hele verden. Hvordan selskapets ingeniører kom frem til beslutningen om å bruke QUIC i produksjonen, hvordan de utførte testene og hva de så etter å ha rullet den ut i produksjon – under kuttet.

Bildene er klikkbare. Liker å lese!

QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen

Uber har en global skala, nemlig 600 byer med tilstedeværelse, i hver av disse er applikasjonen helt avhengig av trådløst Internett fra mer enn 4500 mobiloperatører. Brukerne forventer at appen ikke bare er rask, men i sanntid – for å oppnå dette trenger Uber-appen lav ventetid og en svært pålitelig tilkobling. Akk, men stabelen HTTP / 2 gjør det ikke bra i dynamiske og tapsutsatte trådløse nettverk. Vi innså at i dette tilfellet er lav ytelse direkte relatert til TCP-implementeringer i operativsystemkjerner.

For å løse problemet søkte vi QUIC, en moderne kanalmultipleksingsprotokoll som gir oss mer kontroll over ytelsen til transportprotokollen. For tiden arbeidsgruppen IETF standardiserer QUIC as HTTP / 3.

Etter omfattende testing konkluderte vi med at implementering av QUIC i applikasjonen vår ville resultere i lavere haleforsinkelser sammenlignet med TCP. Vi observerte en reduksjon i området på 10-30 % for HTTPS-trafikk i sjåfør- og passasjerapplikasjoner. QUIC ga oss også ende-til-ende kontroll over brukerpakker.

I denne artikkelen deler vi vår erfaring med å optimalisere TCP for Uber-applikasjoner ved å bruke en stabel som støtter QUIC.

Den nyeste teknologien: TCP

I dag er TCP den mest brukte transportprotokollen for å levere HTTPS-trafikk på Internett. TCP gir en pålitelig strøm av byte, og takler dermed nettverksbelastning og tap av koblingslag. Den utbredte bruken av TCP for HTTPS-trafikk skyldes førstnevntes allestedsnærværende (nesten alle operativsystemer inneholder TCP), tilgjengelighet på de fleste infrastrukturer (som belastningsbalansere, HTTPS-proxyer og CDN-er), og ut-av-boksen-funksjonalitet som er tilgjengelig. på nesten de fleste plattformer og nettverk.

De fleste brukere bruker appen vår mens de er på farten, og TCP-haleforsinkelser var ikke i nærheten av kravene til vår sanntids HTTPS-trafikk. Enkelt sagt, brukere over hele verden har opplevd dette - Figur 1 viser forsinkelser i større byer:

QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen
Figur 1: Tail latency varierer mellom Ubers hovedbyer.

Selv om ventetiden i indiske og brasilianske nettverk var høyere enn i USA og Storbritannia, er halelatens betydelig høyere enn gjennomsnittlig ventetid. Og dette gjelder selv for USA og Storbritannia.

TCP over luft ytelse

TCP ble opprettet for kablet nettverk, det vil si med vekt på svært forutsigbare koblinger. Derimot, trådløst nettverk har sine egne egenskaper og vanskeligheter. For det første er trådløse nettverk utsatt for tap på grunn av interferens og signaldemping. For eksempel er Wi-Fi-nettverk følsomme for mikrobølger, bluetooth og andre radiobølger. Mobilnettverk lider av signaltap (tapt vei) på grunn av refleksjon/absorpsjon av signalet av objekter og bygninger, samt fra innblanding fra naboen celletårn. Dette fører til mer betydelig (4-10 ganger) og mer mangfoldig Rundturstid (RTT) og pakketap sammenlignet med en kablet tilkobling.

For å bekjempe båndbreddesvingninger og tap bruker mobilnettverk vanligvis store buffere for trafikkutbrudd. Dette kan føre til for stor kø, noe som betyr lengre forsinkelser. Svært ofte behandler TCP denne køen som sløsing på grunn av en forlenget timeout, så TCP har en tendens til å videresende og dermed fylle bufferen. Dette problemet er kjent som bufferbloat (overdreven nettverksbuffring, bufferoppblåsthet), og dette er veldig seriøst problem moderne Internett.

Til slutt varierer mobilnettverksytelsen etter operatør, region og tid. I figur 2 samlet vi medianforsinkelsene for HTTPS-trafikk på tvers av celler innenfor et 2-kilometers område. Data samlet inn for to store mobiloperatører i Delhi, India. Som du kan se, varierer ytelsen fra celle til celle. Produktiviteten til en operatør skiller seg også fra produktiviteten til den andre. Dette påvirkes av faktorer som nettverksinngangsmønstre som tar hensyn til tid og plassering, brukermobilitet, samt nettverksinfrastruktur som tar hensyn til tårntetthet og forholdet mellom nettverkstyper (LTE, 3G, etc.).

QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen
Figur 2. Forsinkelser med en radius på 2 km som eksempel. Delhi, India.

Dessuten varierer ytelsen til mobilnettverk over tid. Figur 3 viser median latens etter ukedag. Vi observerte også forskjeller i mindre skala, i løpet av en enkelt dag og time.

QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen
Figur 3. Haleforsinkelser kan variere betydelig mellom dager, men for samme operatør.

Alt det ovennevnte fører til at TCP-ytelsen er ineffektiv i trådløse nettverk. Men før vi leter etter alternativer til TCP, ønsket vi å utvikle en presis forståelse på følgende punkter:

  • er TCP hovedårsaken bak haleforsinkelser i applikasjonene våre?
  • Har moderne nettverk betydelige og varierte rundtursforsinkelser (RTT)?
  • Hva er virkningen av RTT og tap på TCP-ytelse?

TCP-ytelsesanalyse

For å forstå hvordan vi analyserte TCP-ytelse, la oss ta en rask titt på hvordan TCP overfører data fra en sender til en mottaker. Først etablerer avsenderen en TCP-forbindelse ved å utføre en treveis håndtrykk: Avsenderen sender en SYN-pakke, venter på en SYN-ACK-pakke fra mottakeren, og sender deretter en ACK-pakke. En ekstra andre og tredje pass brukes til å etablere TCP-forbindelsen. Mottakeren bekrefter mottak av hver pakke (ACK) for å sikre pålitelig levering.

Hvis en pakke eller ACK går tapt, sender avsenderen på nytt etter et tidsavbrudd (RTO, tidsavbrudd for tilbakesending). RTO beregnes dynamisk basert på ulike faktorer, for eksempel forventet RTT-forsinkelse mellom avsender og mottaker.

QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen
Figur 4. Pakkeutveksling over TCP/TLS inkluderer en retransmisjonsmekanisme.

For å finne ut hvordan TCP presterte i applikasjonene våre, overvåket vi TCP-pakker ved hjelp av tcpdump i en uke på kamptrafikk som kommer fra indiske kantservere. Vi analyserte deretter TCP-tilkoblingene ved hjelp av tcptrace. I tillegg har vi laget en Android-applikasjon som sender emulert trafikk til en testserver, og imiterer ekte trafikk så mye som mulig. Smarttelefoner med denne applikasjonen ble distribuert til flere ansatte, som samlet inn logger over flere dager.

Resultatene fra begge eksperimentene stemte overens med hverandre. Vi så høye RTT-forsinkelser; haleverdier var nesten 6 ganger høyere enn medianverdien; det aritmetiske gjennomsnittet av forsinkelser er mer enn 1 sekund. Mange tilkoblinger gikk med tap, noe som førte til at TCP sendte 3,5 % av alle pakker på nytt. I overbelastede områder som flyplasser og togstasjoner så vi 7 % tap. Disse resultatene sår tvil om den konvensjonelle visdommen som de som brukes i mobilnettverk avanserte videresendingskretser redusere tap betydelig på transportnivå. Nedenfor er testresultatene fra «simulator»-applikasjonen:

Nettverksmålinger
som betyr

RTT, millisekunder [50%,75%, 95%,99%]
[350, 425, 725, 2300]

RTT-divergens, sekunder
I gjennomsnitt ~1,2 s

Pakketap på ustabile tilkoblinger
Gjennomsnittlig ~3.5 % (7 % i overbelastede områder)

Nesten halvparten av disse forbindelsene hadde minst ett pakketap, de fleste av dem SYN- og SYN-ACK-pakker. De fleste TCP-implementeringer bruker en RTO-verdi på 1 sekund for SYN-pakker, som øker eksponentielt for påfølgende tap. Applikasjonsinnlastingstiden kan øke på grunn av at TCP tar lengre tid å etablere tilkoblinger.

Når det gjelder datapakker, reduserer høye RTO-verdier den nyttige utnyttelsen av nettverket i nærvær av forbigående tap i trådløse nettverk. Vi fant ut at den gjennomsnittlige reoverføringstiden er omtrent 1 sekund med en haleforsinkelse på nesten 30 sekunder. Disse høye ventetidene på TCP-nivå forårsaket HTTPS-tidsavbrudd og re-forespørsler, noe som økte nettverksforsinkelsen og ineffektiviteten ytterligere.

Mens den 75. persentilen av målt RTT var rundt 425 ms, var den 75. persentilen for TCP nesten 3 sekunder. Dette antyder at tapet førte til at TCP tok 7-10 passeringer for å overføre data. Dette kan være en konsekvens av ineffektiv RTO-beregning, TCPs manglende evne til raskt å reagere på tap siste pakker i vinduet og ineffektiviteten til overbelastningskontrollalgoritmen, som ikke skiller mellom trådløstap og tap på grunn av overbelastning av nettverket. Nedenfor er resultatene av TCP tapstester:

TCP-pakketapstatistikk
Verdi

Prosentandel av forbindelser med minst 1 pakketap
45%

Andel tilkoblinger med tap under tilkoblingsoppsett
30%

Andel tilkoblinger med tap under datautveksling
76%

Fordeling av forsinkelser i reoverføring, sekunder [50%, 75%, 95%,99%] [1, 2.8, 15, 28]

Fordeling av antall reoverføringer for én pakke eller TCP-segment
[1,3,6,7]

Anvendelse av QUIC

Opprinnelig utviklet av Google, QUIC er en flertråds moderne transportprotokoll som kjører på toppen av UDP. For øyeblikket er QUIC inne standardiseringsprosess (vi skrev allerede at det er, som det var, to versjoner av QUIC, nysgjerrig kan følge linken – ca. oversetter). Som vist i figur 5 er QUIC plassert under HTTP/3 (faktisk er HTTP/2 på toppen av QUIC HTTP/3, som nå blir intensivt standardisert). Den erstatter delvis HTTPS- og TCP-lagene ved å bruke UDP til å danne pakker. QUIC støtter kun sikker dataoverføring da TLS er fullt innebygd i QUIC.

QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen
Figur 5: QUIC kjører under HTTP/3, og erstatter TLS, som tidligere kjørte under HTTP/2.

Nedenfor er grunnene som overbeviste oss om å bruke QUIC for TCP-forsterkning:

  • 0-RTT-forbindelse etablering. QUIC tillater gjenbruk av autorisasjoner fra tidligere tilkoblinger, og reduserer antallet sikkerhetshåndtrykk. I fremtiden TLS1.3 vil støtte 0-RTT, men et treveis TCP-håndtrykk vil fortsatt være nødvendig.
  • overvinne HoL-blokkering. HTTP/2 bruker én TCP-tilkobling per klient for å forbedre ytelsen, men dette kan føre til HoL-blokkering (head-of-line). QUIC forenkler multipleksing og leverer forespørsler til applikasjonen uavhengig.
  • overbelastningskontroll. QUIC ligger i applikasjonslaget, noe som gjør det enklere å oppdatere hovedtransportalgoritmen som kontrollerer sending basert på nettverksparametere (antall tap eller RTT). De fleste TCP-implementeringer bruker algoritmen KUBISK, som ikke er optimalt for ventetid-sensitiv trafikk. Nylig utviklede algoritmer som BBR, mer nøyaktig modellere nettverket og optimalisere ventetiden. QUIC lar deg bruke BBR og oppdatere denne algoritmen etter hvert som den brukes. forbedring.
  • etterfylling av tap. QUIC kaller to TLP-er (haletapssonde) før RTO utløses - selv når tapene er veldig merkbare. Dette er forskjellig fra TCP-implementeringer. TLP retransmitterer hovedsakelig den siste pakken (eller den nye, hvis det er en) for å utløse rask etterfylling. Håndtering av haleforsinkelser er spesielt nyttig for måten Uber driver nettverket på, nemlig for korte, sporadiske og latenssensitive dataoverføringer.
  • optimalisert ACK. Siden hver pakke har et unikt sekvensnummer, er det ikke noe problem distinksjoner pakker når de sendes på nytt. ACK-pakker inneholder også tid til å behandle pakken og generere en ACK på klientsiden. Disse funksjonene sikrer at QUIC beregner RTT mer nøyaktig. ACK i QUIC støtter opptil 256 bånd NAKKE, som hjelper avsenderen med å være mer motstandsdyktig mot pakkeblanding og bruke færre byte i prosessen. Selektiv ACK (POSEN) i TCP løser ikke dette problemet i alle tilfeller.
  • tilkoblingsmigrering. QUIC-tilkoblinger identifiseres av en 64-bits ID, så hvis en klient endrer IP-adresser, kan den gamle tilkoblings-IDen fortsette å brukes på den nye IP-adressen uten avbrudd. Dette er en veldig vanlig praksis for mobilapplikasjoner der brukeren bytter mellom Wi-Fi og mobiltilkoblinger.

Alternativer til QUIC

Vi vurderte alternative tilnærminger for å løse problemet før vi valgte QUIC.

Det første vi prøvde var å distribuere TPC PoPs (Points of Presence) for å avslutte TCP-tilkoblinger nærmere brukerne. I hovedsak avslutter PoP-er en TCP-forbindelse med en mobilenhet nærmere mobilnettverket og sender trafikken tilbake til den opprinnelige infrastrukturen. Ved å avslutte TCP nærmere, kan vi potensielt redusere RTT og sikre at TCP er mer responsivt til et dynamisk trådløst miljø. Eksperimentene våre har imidlertid vist at det meste av RTT og tap kommer fra mobilnettverk, og bruken av PoP-er gir ikke betydelig ytelsesforbedring.

Vi så også på innstilling av TCP-parametere. Det var vanskelig å sette opp en TCP-stack på våre heterogene edge-servere fordi TCP har ulike implementeringer på tvers av forskjellige OS-versjoner. Det var vanskelig å implementere dette og teste ulike nettverkskonfigurasjoner. Konfigurering av TCP direkte på mobile enheter var ikke mulig på grunn av manglende tillatelser. Enda viktigere, funksjoner som 0-RTT-tilkoblinger og forbedret RTT-prediksjon er avgjørende for protokollens arkitektur, og derfor er det umulig å oppnå betydelige fordeler ved å justere TCP alene.

Til slutt evaluerte vi flere UDP-baserte protokoller som feilsøker videostrømming – vi ønsket å se om disse protokollene ville hjelpe i vårt tilfelle. Dessverre manglet de sterkt i mange sikkerhetsinnstillinger, og krevde også en ekstra TCP-tilkobling for metadata og kontrollinformasjon.

Vår forskning har vist at QUIC kanskje er den eneste protokollen som kan hjelpe med problemet med Internett-trafikk, samtidig som det tas hensyn til både sikkerhet og ytelse.

Integrering av QUIC i plattformen

For å lykkes med å bygge inn QUIC og forbedre applikasjonsytelsen i dårlige tilkoblingsmiljøer, erstattet vi den gamle stabelen (HTTP/2 over TLS/TCP) med QUIC-protokollen. Vi brukte nettverksbiblioteket Cronet av Chromium-prosjekter, som inneholder den originale Google-versjonen av protokollen - gQUIC. Denne implementeringen blir også stadig forbedret for å følge den nyeste IETF-spesifikasjonen.

Vi integrerte Cronet først i Android-appene våre for å legge til støtte for QUIC. Integrasjonen ble utført på en slik måte at migrasjonskostnadene ble redusert så mye som mulig. I stedet for å fullstendig erstatte den gamle nettverksstabelen som brukte biblioteket OkHttp, har vi integrert Cronet UNDER OkHttp API-rammeverket. Ved å gjøre integrasjonen på denne måten unngikk vi endringer i nettverksanropene våre (som brukes av retrofit) på API-nivå.

I likhet med tilnærmingen for Android-enheter, implementerte vi Cronet i Uber-apper på iOS, og fanget opp HTTP-trafikk fra nettverket APIved hjelp av NSURL-protokoll. Denne abstraksjonen, levert av iOS Foundation, håndterer protokollspesifikke URL-data og sikrer at vi kan integrere Cronet i iOS-applikasjonene våre uten betydelige migreringskostnader.

Fullfører QUIC på Google Cloud Balancers

På backend-siden leveres QUIC-fullføring av Google Cloud Load Balancing-infrastrukturen, som bruker alt-svc overskrifter som svar på støtte QUIC. Generelt legger balanseren en alt-svc-header til hver HTTP-forespørsel, og dette validerer allerede QUIC-støtte for domenet. Når en Cronet-klient mottar et HTTP-svar med denne overskriften, bruker den QUIC for påfølgende HTTP-forespørsler til det domenet. Når balanseren har fullført QUIC, sender infrastrukturen vår eksplisitt denne handlingen over HTTP2/TCP til datasentrene våre.

Ytelse: Resultater

Utdataytelse er hovedårsaken til vårt søk etter en bedre protokoll. Til å begynne med laget vi et stand med nettverksemuleringfor å finne ut hvordan QUIC vil oppføre seg under ulike nettverksprofiler. For å teste QUICs ytelse på virkelige nettverk, kjørte vi eksperimenter mens vi kjørte rundt i New Delhi ved å bruke emulert nettverkstrafikk veldig lik HTTP-anrop i passasjerappen.

Eksperiment 1

Utstyr for eksperimentet:

  • test Android-enheter med OkHttp- og Cronet-stabler for å sikre at vi tillater HTTPS-trafikk over henholdsvis TCP og QUIC;
  • en Java-basert emuleringsserver som sender samme type HTTPS-hoder i svar og laster klientenheter for å motta forespørsler fra dem;
  • skyproxyer som er fysisk plassert nær India for å avslutte TCP- og QUIC-forbindelser. Mens for TCP-avslutning brukte vi en omvendt proxy på Nginx, var det vanskelig å finne en åpen kildekode omvendt proxy for QUIC. Vi bygde en omvendt proxy for QUIC selv ved å bruke den grunnleggende QUIC-stakken fra Chromium og publisert den til krom som åpen kildekode.

QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsenQUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen
Figur 6. TCP vs QUIC road testsuite besto av Android-enheter med OkHttp og Cronet, skyproxyer for å avslutte tilkoblinger og en emuleringsserver.

Eksperiment 2

Da Google gjorde QUIC tilgjengelig med Google Cloud Load Balancing, brukte vi samme inventar, men med én modifikasjon: i stedet for NGINX, tok vi Google lastbalansere for å avslutte TCP- og QUIC-tilkoblinger fra enheter, samt for å rute HTTPS-trafikk til emuleringsserveren. Balansere er distribuert over hele verden, men bruker PoP-serveren nærmest enheten (takket være geolokalisering).

QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen
Figur 7. I det andre eksperimentet ønsket vi å sammenligne fullføringsforsinkelsen til TCP og QUIC: bruk av Google Cloud og bruk av cloud proxy.

Som et resultat ventet flere avsløringer oss:

  • terminering via PoP forbedret TCP-ytelse. Siden balansere avslutter TCP-forbindelser nærmere brukere og er svært optimalisert, resulterer dette i lavere RTT-er, noe som forbedrer TCP-ytelsen. Og selv om QUIC ble mindre påvirket, overgikk den fortsatt TCP når det gjelder å redusere halelatens (med 10-30 prosent).
  • haler påvirkes nettverkshopp. Selv om vår QUIC-proxy var lenger unna enhetene (omtrent 50 ms høyere ventetid) enn Googles belastningsbalansere, leverte den lignende ytelse – en 15 % reduksjon i ventetid mot en 20 % reduksjon i 99. persentilen for TCP. Dette tyder på at den siste mile-overgangen er en flaskehals i nettverket.

QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsenQUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen
Figur 8: Resultater fra to eksperimenter viser at QUIC overgår TCP betydelig.

Bekjemp trafikken

Inspirert av eksperimentering har vi implementert QUIC-støtte i våre Android- og iOS-applikasjoner. Vi gjennomførte A/B-tester for å bestemme virkningen av QUIC i byene der Uber opererer. Generelt så vi en betydelig reduksjon i haleforsinkelser på tvers av både regioner, teleoperatører og nettverkstype.

Grafene nedenfor viser de prosentvise forbedringene i haler (95 og 99 persentiler) etter makroregion og ulike nettverkstyper - LTE, 3G, 2G.
QUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsenQUIC-protokollen i aksjon: hvordan Uber implementerte den for å optimalisere ytelsen
Figur 9. I kamptester overgikk QUIC TCP når det gjelder latens.

Bare fremover

Kanskje dette bare er begynnelsen - lanseringen av QUIC i produksjon har gitt fantastiske muligheter til å forbedre applikasjonsytelsen i både stabile og ustabile nettverk, nemlig:

Økt dekning

Etter å ha analysert ytelsen til protokollen på ekte trafikk, så vi at omtrent 80 % av øktene brukte QUIC for Alle forespørsler, mens 15 % av øktene brukte en kombinasjon av QUIC og TCP. Vi antar at kombinasjonen skyldes at Cronet-biblioteket har gått tilbake til TCP, siden det ikke kan skille mellom reelle UDP-feil og dårlige nettverksforhold. Vi ser for tiden på en løsning på dette problemet mens vi jobber mot den påfølgende implementeringen av QUIC.

QUIC-optimalisering

Trafikk fra mobilapper er latenssensitiv, men ikke båndbreddesensitiv. Dessuten brukes applikasjonene våre primært på mobilnettverk. Basert på eksperimenter er haleforsinkelser fortsatt høye selv om du bruker en proxy for å avslutte TCP og QUIC nær brukere. Vi leter aktivt etter måter å forbedre overbelastningshåndtering og forbedre effektiviteten til QUIC-algoritmer for tapsgjenoppretting.

Med disse og flere andre forbedringer planlegger vi å forbedre brukeropplevelsen uavhengig av nettverk og region, og gjøre praktisk og sømløs pakketransport mer tilgjengelig over hele verden.

Kilde: www.habr.com

Legg til en kommentar