Det er meget interessant at følge med i QUIC-protokollen, derfor elsker vi at skrive om den. Men hvis de tidligere publikationer om QUIC mere havde en historisk (lokalsamfunds- hvis du vil) karakter og teknisk indhold, er vi i dag glade for at offentliggøre en anden type oversættelse – vi vil tale om den reelle anvendelse af protokollen i 2019. Og det handler ikke om små infrastrukturer, der er baseret i en hypotetisk garage, men om Uber, som opererer næsten over hele verden. Hvordan ingeniørerne i virksomheden besluttede at bruge QUIC i produktionen, hvordan de gennemførte tests, og hvad de observerede efter implementeringen i produktionen – læs videre.
Billederne er klikbare. God fornøjelse med læsningen!
Uber er et globalt fænomen, til stede i 600 byer, hvor app'en fuldstændig er afhængig af trådløst internet fra mere end 4500 mobiloperatører. Brugerne forventer, at app'en ikke bare fungerer hurtigt, men også i realtid – for at sikre dette har Uber brug for lave forsinkelser og en meget pålidelig forbindelse. Desværre klarer stakken sig dårligt i dynamiske og tabssvage trådløse netværk. Vi har erkendt, at i dette tilfælde er den lave ydeevne direkte relateret til TCP-implementationer i operativsystemernes kerner.
For at løse problemet anvendte vi , en moderne protokol med kanal-multiplexing, der giver os mere kontrol over transportprotokollens ydeevne. På nuværende tidspunkt arbejder arbejdsgruppen på at standardisere QUIC som .
Efter omfattende tests nåede vi frem til, at implementeringen af QUIC i vores applikation vil reducere "hale"-forsinkelserne sammenlignet med TCP. Vi observerede en reduktion i størrelsesordenen 10-30% for HTTPS-trafik i eksemplet med chauffør- og passagerapplikationerne. QUIC gav os også fuld kontrol over brugerpakkerne.
I denne artikel deler vi erfaringen med optimering af TCP for Uber-applikationer ved hjælp af en stak, der understøtter QUIC.
Den nyeste teknologi: TCP
I dag er TCP den mest anvendte transportprotokol til levering af HTTPS-trafik på internettet. TCP sikrer en pålidelig byte-strøm, hvilket håndterer netværksbelastning og tab i kanalniveau. Den brede anvendelse af TCP til HTTPS-trafik kan forklares med dens allestedsnærværende tilstedeværelse (næsten ethvert operativsystem indeholder TCP), tilgængelighed på størstedelen af infrastrukturen (for eksempel på belastningsbalancere, HTTPS-proxyer og CDN) og funktionaliteten "ud af boksen", der næsten er tilgængelig på de fleste platforme og netværk.
De fleste brugere bruger vores app på farten, og "haleforsinkelserne" i TCP har været langt fra kravene til vores HTTPS-trafik i realtid. Med andre ord, dette har brugere verden over oplevet – i Figur 1 er forsinkelserne i store byer afbildet:
Figur 1. Omfanget af "haleforsinkelser" varierer i de store byer, hvor Uber er til stede.
Selvom forsinkelserne i indiske og brasilianske netværk var højere end i USA og Storbritannien, var haleforsinkelserne betydeligt større end de gennemsnitlige forsinkelser. Og dette er også tilfældet for USA og Storbritannien.
TCP's ydeevne over luft
TCP blev skabt til trådbundne netværk, hvilket betyder, at der er fokus på velforudsigelige forbindelser. Men trådløse netværk har sine egne egenskaber og udfordringer. For det første er trådløse netværk følsomme over for tab på grund af interferens og signal dæmpning. For eksempel er Wi-Fi-netværk følsomme over for mikrobølger, bluetooth og andre radiobølger. Mobilnetværk oplever signaltab () på grund af refleksion/absorption af signaler fra objekter og bygninger samt fra nabos . Dette fører til mere betydelige (4-10 gange) og varierende og pakke-tab sammenlignet med en trådbundet forbindelse.
For at tackle udsving i båndbredden og tab bruger mobilnetværk typisk store buffere til trafikspidser. Dette kan føre til overdreven forsinkelse, hvilket betyder større ventetider. Ofte tolker TCP sådanne forsinkelser som tab på grund af en forhøjet timeout, så TCP har en tendens til at retransmittere og dermed fylde bufferen. Dette problem er kendt som (), og dette er et meget den moderne internet.
Endelig varierer ydeevnen i mobilnetværket afhængigt af tjenesteudbyderen, regionen og tidspunkter. I Figur 2 har vi samlet medianen for HTTPS-trafikforsinkelser over mobilmaster inden for en radius af 2 kilometer. Dataene er indsamlet for to af de største mobiludbydere i Delhi, Indien. Som det kan ses, varierer ydeevnen fra mast til mast. Desuden adskiller ydeevnen hos én udbyder sig fra ydeevnen hos den anden. Faktorer som netværksindgangsmønstre med hensyn til tid og sted, brugernes mobilitet samt netværksinfrastrukturen i forhold til mastetæthed og forholdet mellem netværkstyper (LTE, 3G osv.) påvirker dette.
Figur 2. Forsinkelser exemplificeret på en radius af 2 kilometer. Delhi, Indien.
Ydeevnen i mobilnetværk varierer også over tid. I Figur 3 vises medianforsinkelsen i løbet af ugen. Vi har også observeret forskelle i mindre skala – inden for én dag og time.
Figur 3. Tail forsinkelser kan variere betydeligt på forskellige dage, men for den samme udbyder.
Alt det ovenstående fører til, at TCP-ydelsen er ineffektiv i trådløse netværk. Før vi dog søger alternativer til TCP, ønskede vi at opnå en præcis forståelse af følgende punkter:
- Er TCP den primære årsag til tail forsinkelser i vores applikationer?
- Har moderne netværk betydelige og varierede runde tur forsinkelser (RTT)?
- Hvad er indflydelsen af RTT og tab på TCP-ydelsen?
Analyse af TCP-ydelse
For at forstå, hvordan vi analyserede TCP-ydelsen, lad os kort huske, hvordan TCP overfører data fra sender til modtager. Først opretter senderen en TCP-forbindelse ved at udføre en trevejs : afsender sender en SYN-pakke, venter på en SYN-ACK-pakke fra modtageren og sender derefter en ACK-pakke. De to ekstra passager bruges til at etablere TCP-forbindelsen. Modtageren bekræfter modtagelsen af hver pakke (ACK) for at sikre pålidelig levering.
Hvis en pakke eller ACK går tabt, sender afsenderen en retransmission efter en timeout (RTO, ). RTO beregnes dynamisk baseret på forskellige faktorer, for eksempel den forventede RTT-forsinkelse mellem senderen og modtageren.
Figur 4. Pakkeudveksling via TCP/TLS inkluderer retransmissionsmekanismer.
For at bestemme, hvordan TCP fungerede i vores applikationer, sporede vi TCP-pakker ved hjælp af i løbet af en uge på live trafik fra indiske grænseservere. Derefter analyserede vi TCP-forbindelserne med hjælp fra . Derudover skabte vi en Android-applikation, der sender simuleret trafik til en testserver, som i høj grad efterligner ægte trafik. Smartphones med denne applikation blev uddelt til flere medarbejdere, der indsamlede logs i løbet af flere dage.
Resultaterne fra begge eksperimenter var ens. Vi så høje RTT-forsinkelser; tail-værdierne var næsten 6 gange højere end medianen; det gennemsnitlige forsinkelsestid var mere end 1 sekund. Mange forbindelser havde tab, hvilket fik TCP til at retransmittere 3,5% af alle pakker. I områder med overbelastning, såsom lufthavne og stationer, observerede vi 7% tab. Disse resultater sætter spørgsmålstegn ved den almindelige antagelse om, at de avancerede retransmissionsskemaer, der anvendes i mobilnetværk, Netværksmetrikker
RTT, millisekunder [50%,75%, 95%,99%]
Værdier
RTT-variation, sekunder
[350, 425, 725, 2300]
I gennemsnit ~1,2 s
Pakke-tab i ustabile forbindelser
I gennemsnit ~3.5% (7% i overbelastede områder)
Næsten halvdelen af disse forbindelser havde mindst ét pakke-tab, som for det meste var SYN- og SYN-ACK-pakker. De fleste TCP-implementeringer bruger en RTO-værdi på 1 sekund for SYN-pakker, som øges eksponentielt ved efterfølgende tab. Loadingtiden for applikationen kan stige, da TCP vil tage længere tid til at etablere forbindelser.
I tilfælde af datapakker reducerer høje RTO-værdier stærkt den nyttige udnyttelse af netværket ved Midlertidige tab i trådløse netværk. Vi fandt ud af, at den gennemsnitlige retransmissionstid var cirka 1 sekund med en tail-forsinkelse på næsten 30 sekunder. Sådanne høje TCP-forsinkelser forårsagede HTTPS-timeouts og gentagne forespørgsler, hvilket yderligere forøgede forsinkelsen og ineffektiviteten i netværket.
I tilfælde af dataplaner reducerer høje RTO-værdier kraftigt den nyttige udnyttelse af netværket i tilfælde af midlertidige tab i trådløse netværk. Vi har fundet ud af, at den gennemsnitlige retransmissionstid er cirka 1 sekund med en bagvedstående forsinkelse på næsten 30 sekunder. Sådanne høje forsinkelser på TCP-niveau forårsagede HTTPS-timeouts og gentagne anmodninger, hvilket yderligere øgede forsinkelsen og ineffektiviteten af netværket.
Mens 75. percentil af de målte RTT var omkring 425 ms, var 75. percentil for TCP næsten 3 sekunder. Dette antyder, at tabene fik TCP til at lave 7-10 forsøg for at overføre dataene korrekt. Dette kan skyldes en ineffektiv beregning af RTO og TCP's manglende evne til hurtigt at reagere på tab. i vinduet og ineffektiviteten i algoritmen til overbelastningskontrol, som ikke adskiller trådløse tab og tab på grund af netværksbelastning. Nedenfor er resultaterne af TCP-tabstests:
Statistik over TCP-tab
Værdi
Procentdel af forbindelser med mindst 1 tabt pakke
45%
Procentdel af forbindelser med tab under oprettelse af forbindelsen
30%
Procentdel af forbindelser med tab under datatransmission
76%
Fordeling af forsinkelser i retransmission, sekunder [50%, 75%, 95%, 99%]
[1, 2.8, 15, 28]
Fordeling af antal retransmissioner for en pakke eller TCP-segment
[1,3,6,7]
Anvendelse af QUIC
Oprindeligt designet af Google, QUIC er en moderne transportprotokol med flere strømme, der kører over UDP. I øjeblikket er QUIC i (vi har allerede nævnt, at der tilsyneladende findes to versioner af QUIC, nysgerrige – bem. fra oversætteren). Som vist i Figur 5, ligger QUIC under HTTP/3 (faktisk er HTTP/2 over QUIC det, der kaldes HTTP/3, som nu bliver intensivt standardiseret). Det delvist erstatter HTTPS- og TCP-niveauer, idet det bruger UDP til pakkeformatering. QUIC understøtter kun sikker dataoverførsel, da TLS er fuldt integreret i QUIC.

Figur 5: QUIC arbejder under HTTP/3, hvilket erstatter TLS, der tidligere kørte under HTTP/2.
Nedenfor præsenterer vi de grunde, der overbeviste os om at bruge QUIC til at styrke TCP:
- 0-RTT forbindelsesoprettelse. QUIC muliggør genbrug af autorisationer fra tidligere forbindelser, hvilket reducerer antallet af sikkerhedshåndtryk. I fremtiden understøtte 0-RTT, dog vil den tredoble TCP-håndtryksproces stadig være obligatorisk.
- overvindelse af HoL-blokering. HTTP/2 bruger én TCP-forbindelse pr. klient for at forbedre ydeevnen, men dette kan føre til HoL (head-of-line) blokering. QUIC forenkler multiplexering og leverer anmodninger til applikationen uafhængigt af hinanden.
- overbelastningskontrol. QUIC opererer på applikationsniveau og giver mulighed for nemmere opdatering af hovedtransportalgoritmen, der styrer afsendelse baseret på netværksparametre (antal tab eller RTT). De fleste TCP-implementeringer bruger algoritmen , som ikke er optimal til forsinkelsessensitiv trafik. Nyligt udviklede algoritmer som , modellerer netværket mere præcist og optimerer forsinkelserne. QUIC muliggør brugen af BBR og opdatering af denne algoritme, efterhånden som den .
- til at genopfylde tab. QUIC udløser to TLP () før RTO aktiveres - selv når tabene er meget mærkbare. Dette adskiller sig fra TCP-implementeringer. TLP retransmitterer hovedsageligt den sidste pakke (eller en ny, hvis sådan er tilgængelig) for hurtigt at igangsætte genopfyldning. Håndtering af tail-loss er især nyttig for, hvordan Uber arbejder med nettet, nemlig til korte, episodiske og forsinkelsessensitive datatransmissioner.
- optimeret ACK. Da hver pakke har et unikt sekventielt nummer, opstår der ikke problemer med af pakker ved deres retransmission. ACK-pakker indeholder også tid til behandling af pakken og generering af ACK på klientsiden. Disse funktioner sikrer, at QUIC mere præcist beregner RTT. ACK i QUIC understøtter op til 256 intervaller , hvilket hjælper afsenderen med at være mere robust over for pakkeombytning og bruge færre bytes i processen. Selective ACK () i TCP løser ikke dette problem i alle tilfælde.
- forbindelsesmigration. QUIC-forbindelser identificeres ved hjælp af et 64-bit ID, så hvis klienten skifter IP-adresser, kan ID'et fra den gamle forbindelse fortsætte med at blive brugt på den nye IP-adresse uden afbrydelse. Dette er en meget almindelig praksis for mobile applikationer, når brugeren skifter mellem Wi-Fi og mobilforbindelser.
Alternativer til QUIC
Vi har overvejet alternative tilgange til at løse problemet, inden vi valgte QUIC.
Først forsøgte vi at implementere TPC PoPs (Points of Presence) for at afslutte TCP-forbindelser tættere på brugerne. I bund og grund afslutter PoPs TCP-forbindelsen med den mobile enhed tættere på mobilnetværket og proxy-trafikken til den oprindelige infrastruktur. Ved at afslutte TCP tættere kan vi potentielt reducere RTT og være sikre på, at TCP vil reagere mere aktivt på et dynamisk trådløst miljø. Desværre viste vores eksperimenter, at for det meste kom RTT og tab fra mobilnetværkene, og brugen af PoPs giver ikke en betydelig forbedring af ydeevnen.
Vi kiggede også på tuning af TCP-parametre. At justere TCP-stakken på vores heterogene grænsefladeservere var vanskeligt, da TCP har uforenelige implementeringer på forskellige operativsystemversioner. Det var svært at implementere og teste forskellige netværkskonfigurationer. Indstilling af TCP direkte på mobile enheder var umuligt på grund af manglende rettigheder. Endnu vigtigere er, at funktioner som 0-RTT-forbindelser og forbedret RTT-forudsigelse er kritiske for protokolarkitekturen og derfor er det umuligt at opnå betydelige fordele blot ved at justere TCP.
Endelig vurderede vi flere UDP-baserede protokoller, der fejlfinder video streaming – vi ønskede at finde ud af, om disse protokoller ville være nyttige i vores tilfælde. Desværre manglede de mange sikkerhedsindstillinger, og de krævede også en ekstra TCP-forbindelse til metadata og kontrolinformation.
Vores undersøgelser viste, at QUIC næppe er den eneste protokol, der kan hjælpe med Internet-trafikproblemer, mens den tager højde for både sikkerhed og ydeevne.
Integration af QUIC i platformen
For at integrere QUIC succesfuldt og forbedre applikationens ydeevne under dårlige forbindelser, erstattede vi den gamle stak (HTTP/2 over TLS/TCP) med QUIC-protokollen. Vi anvendte netværksbiblioteket af , som indeholder den originale, Google-version af protokollen – gQUIC. Denne implementering forbedres konstant for at følge den nyeste IETF-specifikation.
Først integrerede vi Cronet i vores Android-applikationer for at tilføje støtte til QUIC. Integrationen blev udført på en måde, der minimerede migrationsomkostningerne. I stedet for helt at erstatte den gamle netværksstak, der brugte biblioteket , integrerede vi Cronet UNDER OkHttp API-rammen. Ved at udføre integrationen på denne måde undgik vi ændringer i vores netværksanrop (som bruger ) på API-niveau.
Ligesom med tilgangen til Android-enhederne implementerede vi Cronet i Uber-applikationer på iOS ved at intercept HTTP-trafik fra netværks , ved hjælp af . Denne abstraktion, som tilbydes af iOS Foundation, håndterer protokolspecifikke URL-data og sikrer, at vi kan integrere Cronet i vores iOS-applikationer uden væsentlige migrationsomkostninger.
QUIC-afslutning på Google Cloud-loadbalancere
På backend-siden er QUIC-afslutning sikret af Google Cloud Load balancing-infrastrukturen, som bruger overskrifter i svarene for at understøtte QUIC. Generelt tilføjer loadbalanceren en alt-svc-overskrift til hver HTTP-anmodning og validerer så QUIC-supporten for domænet. Når Cronet-klienten modtager et HTTP-svar med en sådan overskrift, bruger den QUIC til efterfølgende HTTP-anmodninger til dette domæne. Når loadbalanceren afslutter QUIC, sender vores infrastruktur eksplicit denne handling via HTTP2/TCP til vores datacenter.
Ydeevne: resultater
Den ydelser, der leveres, er den primære årsag til vores søgen efter den bedste protokol. For at starte oprettede vi en testopsætning med , for at finde ud af, hvordan QUIC ville opføre sig under forskellige netværksprofiler. For at teste QUICs funktionalitet i reelle netværk udførte vi eksperimenter ved at køre rundt i New Delhi ved hjælp af simuleret netværkstrafik, der mindede meget om HTTP-anrop i passagerapplikationen.
Eksperiment 1
Inventar til eksperimentet:
- testede enheder på Android med OkHttp- og Cronet-stakke for at sikre, at vi sendte HTTPS-trafik via TCP og QUIC henholdsvis;
- Java-baseret simuleringsserver, der sender ensartede HTTPS-overskrifter i svarene og belaster klientenhederne for at modtage forespørgsler fra dem;
- cloudproxyer, der fysisk er placeret tæt på Indien for at afslutte TCP- og QUIC-forbindelser. Mens vi brugte en omvendt proxy til at afslutte TCP, , det var svært at finde en open source reverse proxy til QUIC. Vi har selv samlet en reverse proxy til QUIC ved at bruge QUIC-baserne fra Chromium og den i Chromium som open source.
Figur 6. Testkittet for TCP vs QUIC bestod af Android-enheder med OkHttp og Cronet, cloud proxies til afslutning af forbindelser og en emulatorserver.
Eksperiment 2
Da Google gjorde QUIC tilgængeligt gennem , brugte vi det samme udstyr, men med én modifikation: i stedet for NGINX tog vi Googles load balancers til at afslutte TCP- og QUIC-forbindelser fra enhederne samt til at dirigere HTTPS-trafik til emulatorserveren. Load balancers er spredt over hele verden, men bruger den nærmeste PoP-server til enheden (tak til geolokation).
Figur 7. I det andet eksperiment ønskede vi at sammenligne TCP- og QUIC-afslutningens forsinkelse: ved hjælp af Google Cloud og ved hjælp af vores cloud proxy.
Resultatet bød på flere åbenbaringer:
- afslutning gennem PoP forbedrede TCP-ydelsen. Da load balancers afslutter TCP-forbindelsen tættere på brugerne og er optimaliseret, giver det mindre RTT, hvilket forbedrer TCP-ydelsen. Og selvom dette havde mindre indflydelse på QUIC, slog det stadig TCP i forhold til at reducere hale-forsinkelser (med 10-30 procent).
- på halerne påvirkes . Selvom vores QUIC-proxy var længere væk fra enhederne (forsinkelse cirka 50 ms højere) end Googles load balancers, opnåede den lignende ydeevne – 15 % reduktion i forsinkelser mod 20 % reduktion i 99. percentil hos TCP. Det tyder på, at overgangen på den sidste mile er et flaskehalsproblem i netværksdriften.
Figur 8. Resultaterne af de to eksperimenter viser, at QUIC klart overgår TCP.
Kamp trafik
Inspireret af eksperimenterne implementerede vi QUIC-support i vores Android- og iOS-apps. Vi lavede A/B-test for at bestemme indflydelsen af QUIC i byer, hvor Uber er til stede. Generelt så vi en betydelig reduktion i hale-forsinkelser på tværs af både regioner og mobiloperatører samt netværkstypen.
I graferne nedenfor vises de procentvise forbedringer af halerne (95. og 99. percentil) på tværs af makroregioner og forskellige netværkstyper – LTE, 3G, 2G.
Figur 9. I kamp testene overgik QUIC TCP med hensyn til forsinkelse.
Bare fremad
Dette er nok kun begyndelsen – introduktionen af QUIC i produktion har givet fantastiske muligheder for at forbedre applikationernes ydeevne både i stabile og ustabile netværk, nemlig:
Øget dækning
Ved at analysere protokolens ydeevne på reel trafik, så vi, at cirka 80% af sessionerne succesfuldt brugte QUIC til af alle anmodninger, mens 15% af sessionerne brugte en kombination af QUIC og TCP. Vi antager, at denne kombination opstod, fordi Cronet-biblioteket skifter tilbage til TCP ved tidsoverskud, da det ikke kan skelne mellem ægte UDP-fejl og dårlige netværksforhold. Vi søger i øjeblikket en løsning på dette problem, da vi arbejder på at implementere QUIC yderligere.
Optimering af QUIC
Trafik fra mobile applikationer er følsom over for forsinkelser, men ikke over for båndbredde. Desuden bruges vores applikationer primært i mobilnetværk. Baseret på eksperimenter er hale-forsinkelserne stadig store, selvom der anvendes proxyer til at afslutte TCP og QUIC tæt på brugerne. Vi søger aktivt efter måder at forbedre overbelastningshåndteringen og øge effektiviteten af QUIC-algoritmerne til tabsgenopretning.
Med disse og nogle andre forbedringer planlægger vi at forbedre brugeroplevelsen uanset netværk og region ved at gøre transport af pakker mere tilgængeligt over hele verden.
Kilde: habr.com
