QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda

QUIC-protokollet är extremt intressant att titta på, det är därför vi älskar att skriva om det. Men om tidigare publikationer om QUIC var mer av en historisk (lokal historia, om du så vill) natur och hårdvara, publicerar vi idag gärna en översättning av ett annat slag - vi kommer att prata om den verkliga tillämpningen av protokollet under 2019. Dessutom pratar vi inte om liten infrastruktur baserad i ett så kallat garage, utan om Uber, som verkar nästan över hela världen. Hur företagets ingenjörer kom fram till beslutet att använda QUIC i produktionen, hur de genomförde testerna och vad de såg efter att ha rullat ut det i produktionen - under snittet.

Bilderna är klickbara. Njut av att läsa!

QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda

Uber har en global skala, nämligen 600 städer med närvaro, i var och en av dem är applikationen helt beroende av trådlöst internet från mer än 4500 XNUMX mobiloperatörer. Användare förväntar sig att appen inte bara är snabb, utan i realtid – för att uppnå detta behöver Uber-appen låg latens och en mycket pålitlig anslutning. Ack, men traven HTTP / 2 fungerar inte bra i dynamiska och förlustbenägna trådlösa nätverk. Vi insåg att i det här fallet är låg prestanda direkt relaterad till TCP-implementationer i operativsystemets kärnor.

För att lösa problemet ansökte vi QUIC, ett modernt kanalmultiplexeringsprotokoll som ger oss mer kontroll över transportprotokollets prestanda. För närvarande arbetsgruppen IETF standardiserar QUIC as HTTP / 3.

Efter omfattande tester drog vi slutsatsen att implementering av QUIC i vår applikation skulle resultera i lägre svansfördröjningar jämfört med TCP. Vi observerade en minskning i intervallet 10-30 % för HTTPS-trafik i förar- och passagerarapplikationer. QUIC gav oss också end-to-end kontroll över användarpaket.

I den här artikeln delar vi med oss ​​av vår erfarenhet av att optimera TCP för Uber-applikationer med hjälp av en stack som stöder QUIC.

Den senaste tekniken: TCP

Idag är TCP det mest använda transportprotokollet för att leverera HTTPS-trafik på Internet. TCP tillhandahåller en tillförlitlig ström av byte, och klarar därigenom nätverksstockning och förluster av länklager. Den utbredda användningen av TCP för HTTPS-trafik beror på den förstnämndas överallt (nästan alla operativsystem innehåller TCP), tillgänglighet på de flesta infrastrukturer (som belastningsutjämnare, HTTPS-proxyer och CDN:er) och färdigfunktionalitet som är tillgänglig på nästan de flesta plattformar och nätverk.

De flesta användare använder vår app när de är på språng, och TCP tail latenser var inte i närheten av kraven från vår realtids HTTPS-trafik. Enkelt uttryckt har användare över hela världen upplevt detta - Figur 1 visar förseningar i större städer:

QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda
Figur 1: Svansfördröjning varierar mellan Ubers huvudstäder.

Även om latensen i indiska och brasilianska nätverk var högre än i USA och Storbritannien, är svansfördröjningen betydligt högre än genomsnittlig latens. Och detta gäller även för USA och Storbritannien.

TCP over the air-prestanda

TCP skapades för trådbunden nätverk, det vill säga med tonvikt på mycket förutsägbara länkar. Dock, trådlös nätverk har sina egna egenskaper och svårigheter. För det första är trådlösa nätverk känsliga för förluster på grund av störningar och signaldämpning. Till exempel är Wi-Fi-nätverk känsliga för mikrovågor, bluetooth och andra radiovågor. Mobilnäten lider av signalförlust (förlorad väg) på grund av reflektion/absorption av signalen av föremål och byggnader, samt från interferens från grannlandet celltorn. Detta leder till mer betydande (4-10 gånger) och mer varierande Rundturstid (RTT) och paketförlust jämfört med en trådbunden anslutning.

För att bekämpa bandbreddsfluktuationer och förluster använder cellulära nätverk vanligtvis stora buffertar för trafikskurar. Detta kan leda till överdriven köbildning, vilket innebär längre förseningar. Mycket ofta behandlar TCP denna köning som ett slöseri på grund av en förlängd timeout, så TCP tenderar att vidarebefordra och därigenom fylla bufferten. Detta problem är känt som buffertsvällning (överdriven nätverksbuffring, buffertuppsvällning), och det här är väldigt allvarligt problem modernt internet.

Slutligen varierar det mobila nätverkets prestanda beroende på operatör, region och tid. I figur 2 samlade vi in ​​medianförseningarna för HTTPS-trafik över celler inom ett 2-kilometersintervall. Data insamlad för två stora mobiloperatörer i Delhi, Indien. Som du kan se varierar prestandan från cell till cell. Produktiviteten hos en operatör skiljer sig också från produktiviteten hos den andra. Detta påverkas av faktorer som nätverksinträdesmönster som tar hänsyn till tid och plats, användarmobilitet, samt nätverksinfrastruktur med hänsyn till tornets täthet och förhållandet mellan nätverkstyper (LTE, 3G, etc.).

QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda
Figur 2. Förseningar med en radie på 2 km som exempel. Delhi, Indien.

Dessutom varierar prestandan för cellulära nätverk över tiden. Figur 3 visar medianlatensen per veckodag. Vi observerade också skillnader i mindre skala, inom en enda dag och timme.

QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda
Figur 3. Svansförseningar kan variera avsevärt mellan dagar, men för samma operatör.

Allt ovanstående gör att TCP-prestandan är ineffektiv i trådlösa nätverk. Men innan vi letade efter alternativ till TCP ville vi utveckla en exakt förståelse för följande punkter:

  • är TCP huvudboven bakom svansfördröjningar i våra applikationer?
  • Har moderna nät betydande och varierande förseningar tur och retur (RTT)?
  • Vilken påverkan har RTT och förlust på TCP-prestanda?

TCP-prestandaanalys

För att förstå hur vi analyserade TCP-prestanda, låt oss ta en snabb titt på hur TCP överför data från en avsändare till en mottagare. Först upprättar avsändaren en TCP-anslutning och utför en trevägs handslag: Avsändaren skickar ett SYN-paket, väntar på ett SYN-ACK-paket från mottagaren och skickar sedan ett ACK-paket. Ytterligare ett andra och tredje pass går åt till att upprätta TCP-anslutningen. Mottagaren bekräftar mottagandet av varje paket (ACK) för att säkerställa tillförlitlig leverans.

Om ett paket eller ACK går förlorat sänder avsändaren om efter en timeout (RTO, timeout för återsändning). RTO beräknas dynamiskt baserat på olika faktorer, såsom den förväntade RTT-fördröjningen mellan avsändaren och mottagaren.

QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda
Figur 4. Paketutbyte över TCP/TLS inkluderar en återsändningsmekanism.

För att avgöra hur TCP presterade i våra applikationer övervakade vi TCP-paket med hjälp av tcpdump i en vecka på stridstrafik som kommer från indiska kantservrar. Vi analyserade sedan TCP-anslutningarna med hjälp av tcptrace. Dessutom skapade vi en Android-applikation som skickar emulerad trafik till en testserver och imiterar verklig trafik så mycket som möjligt. Smartphones med denna applikation distribuerades till flera anställda, som samlade in loggar under flera dagar.

Resultaten av båda experimenten överensstämde med varandra. Vi såg höga RTT-latenser; svansvärdena var nästan 6 gånger högre än medianvärdet; det aritmetiska medelvärdet av förseningar är mer än 1 sekund. Många anslutningar gick med förlust, vilket fick TCP att återsända 3,5 % av alla paket. I överbelastade områden som flygplatser och tågstationer såg vi 7 % förluster. Dessa resultat kastar tvivel på den konventionella visdom som de som används i cellulära nätverk avancerade återsändningskretsar avsevärt minska förlusterna på transportnivå. Nedan är testresultaten från "simulator"-applikationen:

Nätverksstatistik
innebörd

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

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

Paketförlust på instabila anslutningar
I genomsnitt ~3.5 % (7 % i överbelastade områden)

Nästan hälften av dessa anslutningar hade minst en paketförlust, de flesta av dem SYN- och SYN-ACK-paket. De flesta TCP-implementeringar använder ett RTO-värde på 1 sekund för SYN-paket, vilket ökar exponentiellt för efterföljande förluster. Programladdningstider kan öka på grund av att TCP tar längre tid att upprätta anslutningar.

När det gäller datapaket minskar höga RTO-värden avsevärt det användbara utnyttjandet av nätverket i närvaro av övergående förluster i trådlösa nätverk. Vi fann att den genomsnittliga återsändningstiden är cirka 1 sekund med en svansfördröjning på nästan 30 sekunder. Dessa höga latenser på TCP-nivå orsakade HTTPS-timeout och återförfrågningar, vilket ytterligare ökade nätverkslatens och ineffektivitet.

Medan den 75:e percentilen av uppmätt RTT var cirka 425 ms, var den 75:e percentilen för TCP nästan 3 sekunder. Detta antyder att förlusten gjorde att TCP tog 7-10 pass för att framgångsrikt överföra data. Detta kan vara en konsekvens av ineffektiv RTO-beräkning, TCP:s oförmåga att snabbt reagera på förlust senaste paketen i fönstret och ineffektiviteten i algoritmen för överbelastningskontroll, som inte skiljer mellan trådlösa förluster och förluster på grund av överbelastning i nätverket. Nedan är resultaten av TCP-förlusttester:

TCP-paketförluststatistik
Värde

Andel anslutningar med minst 1 paketförlust
45%

Procentandel av anslutningar med förluster under anslutningsuppsättning
30%

Andel anslutningar med förluster under datautbyte
76%

Fördelning av fördröjningar i återsändning, sekunder [50%, 75%, 95%,99%] [1, 2.8, 15, 28]

Fördelning av antalet återsändningar för ett paket eller TCP-segment
[1,3,6,7]

Tillämpning av QUIC

Ursprungligen utvecklat av Google, QUIC är ett flertrådigt modernt transportprotokoll som körs ovanpå UDP. För närvarande är QUIC inne standardiseringsprocessen (vi skrev redan att det finns, liksom, två versioner av QUIC, nyfiken kan följa länken - cirka. översättare). Som visas i figur 5 placeras QUIC under HTTP/3 (i själva verket är HTTP/2 ovanpå QUIC HTTP/3, som nu intensivt standardiseras). Det ersätter delvis HTTPS- och TCP-lagren genom att använda UDP för att bilda paket. QUIC stöder endast säker dataöverföring eftersom TLS är helt inbyggt i QUIC.

QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda
Figur 5: QUIC körs under HTTP/3 och ersätter TLS, som tidigare kördes under HTTP/2.

Nedan är skälen som övertygade oss att använda QUIC för TCP-förstärkning:

  • 0-RTT-anslutning. QUIC tillåter återanvändning av behörigheter från tidigare anslutningar, vilket minskar antalet säkerhetshandslag. I framtiden TLS1.3 kommer att stödja 0-RTT, men ett trevägs TCP-handslag kommer fortfarande att krävas.
  • övervinna HoL-blockering. HTTP/2 använder en TCP-anslutning per klient för att förbättra prestandan, men detta kan leda till HoL-blockering (head-of-line). QUIC förenklar multiplexering och levererar förfrågningar till applikationen oberoende.
  • trängselkontroll. QUIC finns i applikationslagret, vilket gör det enklare att uppdatera huvudtransportalgoritmen som styr sändning baserat på nätverksparametrar (antal förluster eller RTT). De flesta TCP-implementeringar använder algoritmen KUBISK, vilket inte är optimalt för latenskänslig trafik. Nyligen utvecklade algoritmer som BBR, modellera nätverket mer exakt och optimera latensen. QUIC låter dig använda BBR och uppdatera denna algoritm när den används. förbättra.
  • påfyllning av förluster. QUIC anropar två TLP:er (svansförlustsond) innan RTO utlöses - även när förlusterna är mycket märkbara. Detta skiljer sig från TCP-implementationer. TLP återsänder huvudsakligen det sista paketet (eller det nya, om det finns ett) för att utlösa snabb påfyllning. Att hantera svansförseningar är särskilt användbart för hur Uber driver sitt nätverk, nämligen för korta, sporadiska och latenskänsliga dataöverföringar.
  • optimerad ACK. Eftersom varje paket har ett unikt sekvensnummer är det inga problem distinktioner paket när de återsänds. ACK-paket innehåller också tid för att bearbeta paketet och generera ett ACK på klientsidan. Dessa funktioner säkerställer att QUIC beräknar RTT mer exakt. ACK i QUIC stöder upp till 256 band NACK, vilket hjälper avsändaren att vara mer motståndskraftig mot paketblandning och använda färre byte i processen. Selektiv ACK (SÄCK) i TCP löser inte detta problem i alla fall.
  • anslutningsmigrering. QUIC-anslutningar identifieras av ett 64-bitars ID, så om en klient ändrar IP-adresser kan det gamla anslutnings-ID:t fortsätta att användas på den nya IP-adressen utan avbrott. Detta är en mycket vanlig praxis för mobilapplikationer där användaren växlar mellan Wi-Fi och mobilanslutningar.

Alternativ till QUIC

Vi övervägde alternativa tillvägagångssätt för att lösa problemet innan vi valde QUIC.

Det första vi försökte var att distribuera TPC PoPs (Points of Presence) för att avsluta TCP-anslutningar närmare användarna. I huvudsak avslutar PoP en TCP-anslutning med en mobil enhet närmare det mobila nätverket och skickar trafiken tillbaka till den ursprungliga infrastrukturen. Genom att avsluta TCP närmare kan vi potentiellt minska RTT och säkerställa att TCP är mer lyhörd för en dynamisk trådlös miljö. Våra experiment har dock visat att det mesta av RTT och förlust kommer från cellulära nätverk och användningen av PoP ger ingen betydande prestandaförbättring.

Vi tittade också på justering av TCP-parametrar. Att sätta upp en TCP-stack på våra heterogena edge-servrar var svårt eftersom TCP har olika implementeringar över olika OS-versioner. Det var svårt att implementera detta och testa olika nätverkskonfigurationer. Att konfigurera TCP direkt på mobila enheter var inte möjligt på grund av bristande behörighet. Ännu viktigare är att funktioner som 0-RTT-anslutningar och förbättrad RTT-förutsägelse är avgörande för protokollets arkitektur, och därför är det omöjligt att uppnå betydande fördelar genom att justera TCP enbart.

Slutligen utvärderade vi flera UDP-baserade protokoll som felsöker videoströmning – vi ville se om dessa protokoll skulle hjälpa i vårt fall. Tyvärr saknades de kraftigt i många säkerhetsinställningar och krävde även en extra TCP-anslutning för metadata och kontrollinformation.

Vår forskning har visat att QUIC kanske är det enda protokollet som kan hjälpa till med problemet med internettrafik, samtidigt som man tar hänsyn till både säkerhet och prestanda.

Integrering av QUIC i plattformen

För att framgångsrikt bädda in QUIC och förbättra applikationsprestanda i dåliga anslutningsmiljöer ersatte vi den gamla stacken (HTTP/2 över TLS/TCP) med QUIC-protokollet. Vi använde nätverksbiblioteket Cronet av Chromium-projekt, som innehåller den ursprungliga Google-versionen av protokollet - gQUIC. Denna implementering förbättras också ständigt för att följa den senaste IETF-specifikationen.

Vi integrerade först Cronet i våra Android-appar för att lägga till stöd för QUIC. Integrationen genomfördes på ett sådant sätt att migrationskostnaderna minskade så mycket som möjligt. Istället för att helt ersätta den gamla nätverksstacken som använde biblioteket OkHttp, vi har integrerat Cronet UNDER OkHttp API-ramverket. Genom att göra integrationen på detta sätt undvek vi ändringar i våra nätverkssamtal (som används av Retrofit) på API-nivå.

I likhet med tillvägagångssättet för Android-enheter, implementerade vi Cronet i Uber-appar på iOS, avlyssnade HTTP-trafik från nätverket APIanvänder sig av NSURL-protokoll. Denna abstraktion, som tillhandahålls av iOS Foundation, hanterar protokollspecifika URL-data och säkerställer att vi kan integrera Cronet i våra iOS-applikationer utan betydande migreringskostnader.

Slutför QUIC på Google Cloud Balancers

På backend-sidan tillhandahålls QUIC-slutförandet av Google Cloud Load Balancing Infrastructure, som använder alt-svc rubriker som svar på support QUIC. I allmänhet lägger balanseraren till en alt-svc-rubrik till varje HTTP-begäran, och detta validerar redan QUIC-stöd för domänen. När en Cronet-klient tar emot ett HTTP-svar med denna rubrik, använder den QUIC för efterföljande HTTP-förfrågningar till den domänen. När balansören har slutfört QUIC, skickar vår infrastruktur uttryckligen denna åtgärd över HTTP2/TCP till våra datacenter.

Prestanda: Resultat

Utdataprestanda är huvudskälet till vårt sökande efter ett bättre protokoll. Till att börja med skapade vi en monter med nätverksemuleringför att ta reda på hur QUIC kommer att bete sig under olika nätverksprofiler. För att testa QUIC:s prestanda på verkliga nätverk, körde vi experiment medan vi körde runt i New Delhi med emulerad nätverkstrafik som mycket liknar HTTP-anrop i passagerarappen.

Experiment 1

Utrustning för experimentet:

  • testa Android-enheter med OkHttp- och Cronet-stackar för att säkerställa att vi tillåter HTTPS-trafik över TCP respektive QUIC;
  • en Java-baserad emuleringsserver som skickar samma typ av HTTPS-rubriker i svar och laddar klientenheter för att ta emot förfrågningar från dem;
  • molnproxy som är fysiskt placerad nära Indien för att avsluta TCP- och QUIC-anslutningar. Medan vi för TCP-uppsägning använde en omvänd proxy på nginx, var det svårt att hitta en omvänd proxy med öppen källkod för QUIC. Vi byggde själva en omvänd proxy för QUIC med den grundläggande QUIC-stacken från Chromium och publicerat den till krom som öppen källkod.

QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestandaQUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda
Figur 6. TCP vs QUIC vägtestsviten bestod av Android-enheter med OkHttp och Cronet, molnproxy för att avsluta anslutningar och en emuleringsserver.

Experiment 2

När Google gjorde QUIC tillgängligt med Google Cloud Load Balancing, vi använde samma inventering, men med en modifiering: istället för NGINX tog vi Google lastbalanserare för att avsluta TCP- och QUIC-anslutningar från enheter, samt för att dirigera HTTPS-trafik till emuleringsservern. Balanserare är distribuerade över hela världen, men använder PoP-servern närmast enheten (tack vare geolokalisering).

QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda
Figur 7. I det andra experimentet ville vi jämföra färdigställandefördröjningen för TCP och QUIC: att använda Google Cloud och att använda vår molnproxy.

Som ett resultat väntade flera avslöjanden på oss:

  • uppsägning via PoP förbättrad TCP-prestanda. Eftersom balanserare avslutar TCP-anslutningar närmare användarna och är mycket optimerade, resulterar detta i lägre RTT, vilket förbättrar TCP-prestandan. Och även om QUIC påverkades mindre, överträffade den fortfarande TCP när det gäller att minska svansfördröjningen (med 10-30 procent).
  • svansar påverkas nätverkshopp. Även om vår QUIC-proxy var längre bort från enheterna (cirka 50 ms högre latens) än Googles belastningsutjämnare, levererade den liknande prestanda – en 15 % minskning av latensen jämfört med en 20 % minskning av den 99:e percentilen för TCP. Detta tyder på att den sista milsövergången är en flaskhals i nätverket.

QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestandaQUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda
Figur 8: Resultat från två experiment visar att QUIC avsevärt överträffar TCP.

Bekämpa trafik

Inspirerade av experiment har vi implementerat QUIC-stöd i våra Android- och iOS-applikationer. Vi genomförde A/B-tester för att fastställa effekten av QUIC i de städer där Uber är verksamt. Generellt sett såg vi en betydande minskning av slutförseningar i både regioner, telekomoperatörer och nätverkstyp.

Graferna nedan visar de procentuella förbättringarna i svansar (95 och 99 percentiler) per makroregion och olika nätverkstyper - LTE, 3G, 2G.
QUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestandaQUIC-protokollet i aktion: hur Uber implementerade det för att optimera prestanda
Figur 9. I stridstester överträffade QUIC TCP när det gäller latens.

Bara framåt

Kanske är detta bara början - lanseringen av QUIC i produktion har gett fantastiska möjligheter att förbättra applikationsprestanda i både stabila och instabila nätverk, nämligen:

Ökad täckning

Efter att ha analyserat protokollets prestanda på verklig trafik såg vi att cirka 80 % av sessionerna framgångsrikt använde QUIC för Alla förfrågningar, medan 15 % av sessionerna använde en kombination av QUIC och TCP. Vi antar att kombinationen beror på att Cronet-bibliotekets timeout går tillbaka till TCP, eftersom det inte kan skilja mellan verkliga UDP-fel och dåliga nätverksförhållanden. Vi undersöker för närvarande en lösning på detta problem när vi arbetar mot den efterföljande implementeringen av QUIC.

QUIC optimering

Trafik från mobilappar är latenskänslig, men inte bandbreddskänslig. Dessutom används våra applikationer främst på mobilnät. Baserat på experiment är svanslatenserna fortfarande höga även om man använder en proxy för att avsluta TCP och QUIC nära användarna. Vi letar aktivt efter sätt att förbättra överbelastningshanteringen och förbättra effektiviteten hos QUIC förluståterställningsalgoritmer.

Med dessa och flera andra förbättringar planerar vi att förbättra användarupplevelsen oavsett nätverk och region, vilket gör bekväm och sömlös pakettransport mer tillgänglig över hela världen.

Källa: will.com

Lägg en kommentar