Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu

Protokol QUIC je nesmírně zajímavý, proto o něm rádi píšeme. Zatímco předchozí publikace o QUIC měly spíše historický (pokud chcete, místní) charakter a technické zaměření, dnes máme radost, že můžeme publikovat překlad jiného druhu – zaměříme se na skutečné použití protokolu v roce 2019. A to nejen pro malou infrastrukturu, která by mohla být v garáži, ale pro Uber, jenž působí téměř po celém světě. Jak inženýři společnosti dospěli k rozhodnutí použít QUIC v produkci, jak prováděli testy a co zjistili po nasazení do produkce – v článku.

Obrázky jsou klikatelné. Přejeme příjemné čtení!

Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu

Uber má globální dosah, konkrétně ve 600 městech, kde se aplikace plně spoléhá na bezdrátový internet více než 4500 mobilních operátorů. Uživatelé očekávají, že aplikace bude fungovat nejen rychle, ale v reálném čase – aby toho dosáhli, potřebuje aplikace Uber nízké latence a velmi spolehlivé připojení. Bohužel však protokol HTTP/2 se špatně osvědčuje v dynamických a ztrátových bezdrátových sítích. Uvědomili jsme si, že v tomto případě je nízký výkon přímo spojen s implementacemi TCP v jádrech operačních systémů.

Abychom tento problém vyřešili, použili jsme QUIC, moderní protokol s multiplexací kanálů, který nám poskytuje větší kontrolu nad výkonem přenosového protokolu. V současné době pracovní skupina IETF standardizuje QUIC jako HTTP/3.

Po podrobných testech jsme dospěli k závěru, že implementace QUIC do naší aplikace sníží "chvostové" latence ve srovnání s TCP. Sledujeme snížení v rozmezí 10–30 % pro HTTPS provoz na příkladu aplikací pro řidiče a pasažéry. Také nám QUIC poskytl komplexní kontrolu nad uživatelskými pakety.

V tomto článku se podělíme o zkušenosti s optimalizací TCP pro aplikace Uber pomocí stacku, který podporuje QUIC.

Poslední slovo techniky: TCP

Dnes je TCP nejpoužívanějším transportním protokolem pro doručování HTTPS provozu v síti Internet. TCP zajišťuje spolehlivý tok bytů, čímž se vyrovnává s přetížením sítě a ztrátami na kanálové úrovni. Široké užití TCP pro HTTPS provoz vysvětluje jeho všudypřítomnost (téměř každý operační systém obsahuje TCP), dostupnost na většině infrastruktury (například na vyvažovačích zatížení, HTTPS proxy a CDN) a funkčnost „z krabice“, která je k dispozici téměř na většině platforem a sítí.

Většina uživatelů používá naši aplikaci na cestách a „ocasové“ latence TCP byly daleko od požadavků našeho HTTPS provozu v reálném čase. Jednoduše řečeno, s tím se setkávali uživatelé po celém světě – na Obrázku 1 jsou uvedeny latence v hlavních městech:

Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu
Obrázek 1. Velikost „ocáskových“ zpoždění se liší v hlavních městech návštěvy Uberu.

I když latency v indických a brazilských sítích byly větší než v USA a Velké Británii, ocasové latence jsou významně větší než průměrné latence. A to platí i pro USA a Velkou Británii.

Výkonnost TCP ve vzduchu

TCP byl vytvořen pro drátové sítě, což znamená důraz na dobře předvídatelné odkazy. Nicméně, bezdrátové sítě mají své vlastní specifika a obtíže. Za prvé, bezdrátové sítě jsou citlivé na ztráty způsobené rušením a útlumem signálu. Například Wi-Fi sítě jsou citlivé na mikrovlny, bluetooth a další radiové vlny. Mobilní sítě trpí ztrátou signálu (ztráta cesty) kvůli odrazu/pohlcování signálu předměty a budovami, stejně jako kvůli rušení od sousedních mobilních vysílačů. To vede k významnějším (4-10x) a různorodým kulatým latencím (RTT) a ztrátám paketů v porovnání s drátovým připojením.

Aby se bojovalo s kolísáním šířky pásma a ztrátami, mobilní sítě obvykle používají velké buffery pro špičky provozu. To může vést k nadměrné frontě, což znamená delší zpoždění. Velmi často TCP takovou frontu interpretuje jako ztrátu vzhledem k zvýšenému timeoutu, proto je TCP náchylný k retransmisím a tím i k zaplnění bufferu. Tento problém je znám jako bufferbloat (nadměrné síťové bufferování, nafouknutí bufferu), a to je velmi závažný problém současného internetu.

Konečně, výkon mobilní sítě se liší v závislosti na operátorovi, regionu a čase. Na Obrázku 2 jsme shromáždili mediánové latence HTTPS provozu podle buněk v rozsahu 2 kilometrů. Data byla shromážděna pro dva největší mobilní operátory v Dillí, Indie. Jak si můžete všimnout, výkon se liší od buňky k buňce. Také výkon jednoho operátora se liší od výkonu druhého. To ovlivňují faktory, jako jsou vzory připojení k síti s ohledem na čas a umístění, mobilita uživatelů, a také síťová infrastruktura zohledňující hustotu věží a poměr typů sítě (LTE, 3G atd.).

Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu
Obrázek 2. Latence na příkladu 2-kilometrového rádiusu. Dillí, Indie.

Také výkon mobilních sítí se v průběhu času mění. Na Obrázku 3 je ukázána mediánová latence podle dnů v týdnu. Také jsme zaznamenali rozdíly v menším měřítku – v rámci jednoho dne a hodiny.

Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu
Obrázek 3. Latence mohou výrazně kolísat v různé dny, ale u stejného operátora.

Vše výše uvedené vede k tomu, že výkon TCP je neefektivní v bezdrátových sítích. Nicméně, než hledat alternativy k TCP, chtěli jsme vypracovat přesné pochopení následujících bodů:

  • je TCP hlavním viníkem latencí v našich aplikacích?
  • Mají moderní sítě nějaké významné a rozmanité krouživé latence (RTT)?
  • Jaký vliv má RTT a ztráty na výkon TCP?

Analýza výkonu TCP

Abychom pochopili, jak jsme analyzovali výkon TCP, připomeňme si krátce, jak TCP přenáší data od odesílatele k příjemci. Nejprve odesílatel naváže TCP spojení pomocí třícestného handshaku: odesílatel odesílá SYN paket, čeká na SYN-ACK paket od příjemce, poté posílá ACK paket. Další druhý a třetí průchod trvá k vytvoření TCP spojení. Příjemce potvrzuje přijetí každého paketu (ACK), aby zajistil spolehlivé doručení.

Pokud je paket nebo ACK ztracen, odesílatel provádí retransmisi po uplynutí časového intervalu (RTO, retransmission timeout). RTO se počítá dynamicky na základě různých faktorů, například na očekávané latenci RTT mezi odesílatelem a příjemcem.

Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu
Obrázek 4. Výměna paketů přes TCP/TLS zahrnuje mechanismus retransmise.

Abychom zjistili, jak TCP fungovalo v našich aplikacích, sledovali jsme TCP pakety pomocí tcpdump během týdne na produkčním provozu pocházejícím z indických hraničních serverů. Poté jsme analyzovali TCP spojení pomocí tcptrace. Dále jsme vytvořili aplikaci pro Android, která posílá simulovaný provoz na testovací server a co nejvíce napodobuje skutečný provoz. Smartphony s touto aplikací byly rozdány několika zaměstnancům, kteří sbírali logy po několik dní.

Výsledky obou experimentů byly v souladu s sebou navzájem. Pozorovali jsme vysoké RTT latence; hodnoty v ocasu byly téměř 6krát vyšší než medián; průměrná latence byla více než 1 sekunda. Mnoho spojení mělo ztráty, což způsobilo, že TCP retransmitovalo 3,5 % všech paketů. V oblastech s přetížením, jako jsou letiště a nádraží, jsme pozorovali ztrátu 7 %. Takové výsledky zpochybňují běžné mínění, že používané v mobilních sítích pokročilé schémy retransmise výrazně snižují ztráty na transportní úrovni. Níže jsou výsledky testů z aplikace-simulátoru:

Síťové metriky
Hodnoty

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

RTT rozptyl, sekundy
Průměrně ~1,2 s

Ztráta paketů v nestabilních spojích
Průměrně ~3,5 % (7 % v oblastech s přetížením)

Téměř v polovině těchto spojení došlo k alespoň jedné ztrátě paketů, většinou to byly SYN a SYN-ACK pakety. Většina implementací TCP používá hodnotu RTO 1 sekundu pro SYN pakety, která se exponenciálně zvyšuje pro následné ztráty. Doba načítání aplikace může vzrůst, protože TCP potřebuje více času na navázání spojení.

V případě datových paketů vysoké hodnoty RTO výrazně snižují efektivitu využití sítě při dočasných ztrátách v bezdrátových sítích. Zjistili jsme, že průměrná doba retransmise je přibližně 1 sekunda s hodnotou v ocasu téměř 30 sekund. Takové vysoké latence na úrovni TCP způsobovaly HTTPS časové limity a opakované požadavky, což dále zvyšovalo latenci a neefektivnost sítě.

Zatímco 75. percentil naměřených RTT byl kolem 425 ms, 75. percentil pro TCP byl téměř 3 sekundy. To naznačuje, že ztráty donutily TCP provést 7-10 pokusů, aby úspěšně předalo data. To může být důsledkem neefektivního výpočtu RTO a neschopnosti TCP rychle reagovat na ztrátu. posledních paketů v okně a neefektivnosti algoritmu řízení přetížení, který nerozlišuje mezi bezdrátovými ztrátami a ztrátami způsobenými přetížením sítě. Níže jsou uvedeny výsledky testů ztrát TCP:

Statistika ztrát paketů TCP
Hodnota

Procento spojení s alespoň 1 ztrátou paketu
45%

Procento spojení se ztrátami během navazování spojení
30%

Procento spojení se ztrátami během výměny dat
76%

Distribuce zpoždění při retransmisích, sekundy [50%, 75%, 95%,99%]
[1, 2.8, 15, 28]

Distribuce počtu retransmisí pro jeden paket nebo TCP segment
[1,3,6,7]

Použití QUIC

Původně navržený společností Google, QUIC je moderní vícestreamový transportní protokol, který pracuje nad UDP. V současnosti je QUIC v procesu standardizace (již jsme psali, že existují jakési dvě verze QUIC, zvědaví mohou projít odkazem – pozn. překladatele). Jak je znázorněno na Obrázku 5, QUIC se nachází pod HTTP/3 (vlastně, HTTP/2 nad QUIC je HTTP/3, které se nyní intenzivně standardizuje). Částečně nahrazuje úrovně HTTPS a TCP, používá UDP pro formování paketů. QUIC podporuje pouze bezpečný přenos dat, protože TLS je plně začleněn do QUIC.

Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu
Obrázek 5: QUIC pracuje pod HTTP/3, nahrazující TLS, které dříve fungovalo pod HTTP/2.

Níže uvádíme důvody, které nás přesvědčily použít QUIC pro posílení TCP:

  • 0-RTT navazování spojení. QUIC umožňuje opětovné použití autorizací z předchozích spojení, čímž snižuje počet handshakeů bezpečnosti. V budoucnu TLS1.3 bude podporovat 0-RTT, nicméně trojstranný TCP handshake stále zůstane povinný.
  • překonání blokování HoL. HTTP/2 používá jedno TCP spojení pro každého klienta, aby zlepšilo výkon, ale to může vést k blokaci HoL (head-of-line). QUIC zjednodušuje multiplexování a doručuje žádosti aplikaci nezávisle na sobě.
  • řízení přetížení. QUIC je na aplikační úrovni, což usnadňuje aktualizaci hlavního algoritmu dopravy, který řídí odesílání na základě parametrů sítě (počet ztrát nebo RTT). Většina realizací TCP používá algoritmus CUBIC, který není optimální pro latenci citlivý provoz. Nedávno vyvinuté algoritmy, jako je BBR, přesněji modelují síť a optimalizují latence. QUIC umožňuje použití BBR a aktualizaci tohoto algoritmu, jak se zdokonaluje.
  • na doplnění ztrát. QUIC vyvolává dva TLP (tail loss probe) předtím, než se spustí RTO – i když jsou ztráty velmi výrazné. To se liší od realizací TCP. TLP zejména přenáší poslední paket (nebo nový, pokud je k dispozici), aby spustil rychlé doplnění. Zpracování konečných zpoždění je zvlášť užitečné pro to, jak Uber pracuje se sítí, konkrétně pro krátké, epizodické a latenci citlivé přenosy dat.
  • optimalizovaný ACK. Protože každý paket má jedinečné sekvenční číslo, nevzniká problém s rozlišováním paketů při jejich přenosu. ACK pakety také obsahují čas pro zpracování paketu a generování ACK na straně klienta. Tyto vlastnosti zajišťují, že QUIC přesněji vypočítává RTT. ACK v QUIC podporuje až 256 rozmezí NACK, což pomáhá odesílateli být odolnější vůči přehazování paketů a používat méně bajtů v procesu. Výběrový ACK (SACK) v TCP tuto problematiku neřeší ve všech případech.
  • migrování spojení. Spojení QUIC se identifikují pomocí 64bitového ID, takže pokud klient mění IP adresy, lze dále používat ID starého spojení na nové IP adrese, bez přerušení. To je velmi běžná praxe pro mobilní aplikace, když uživatel přepíná mezi Wi-Fi a mobilními připojeními.

Alternativy QUIC

Zvažovali jsme alternativní přístupy k vyřešení problému předtím, než jsme si vybrali QUIC.

Nejprve jsme se pokusili nasadit TPC PoPs (Body přítomnosti), abychom ukončili TCP spojení blíže uživatelům. V podstatě PoPs ukončuje TCP spojení s mobilním zařízením blíže k mobilní síti a zprostředkovává provoz k původní infrastruktuře. Ukončením TCP blíže můžeme potenciálně snížit RTT a být si jisti, že TCP bude reagovat aktivněji na dynamické bezdrátové prostředí. Naše experimenty však ukázaly, že většina RTT a ztrát pochází ze mobilních sítí a využití PoPs nepřináší výrazné zlepšení výkonu.

Také jsme se zaměřili na ladění parametrů TCP. Úprava TCP zásobníku na našich heterogenních okrajových serverech byla obtížná, protože TCP má nesrovnatelné implementace v různých verzích OS. Bylo složité to realizovat a otestovat různé síťové konfigurace. Nastavení TCP přímo na mobilních zařízeních nebylo možné kvůli nedostatku oprávnění. Co je ještě důležitější, vlastnosti jako spojení s 0-RTT a vylepšené předpovídání RTT jsou kriticky důležité pro architekturu protokolu a proto není možné dosáhnout žádného podstatného přínosu pouze laděním TCP.

Nakonec jsme posoudili několik protokolů založených na UDP, které odstraňují potíže se streamováním videa – chtěli jsme zjistit, zda tyto protokoly pomohou v našem případě. Bohužel měly velký nedostatek mnoha bezpečnostních nastavení a navíc vyžadovaly další TCP připojení pro metadata a řízení informací.

Naše výzkumy ukázaly, že QUIC je téměř jediný protokol, který může pomoci s problémem internetového provozu, přičemž zohledňuje jak bezpečnost, tak výkon.

Integrace QUIC do platformy

Abychom úspěšně integrovali QUIC a zlepšili výkon aplikace za špatných podmínek připojení, nahradili jsme starou technologii (HTTP/2 nad TLS/TCP) protokolem QUIC. Využili jsme síťovou knihovnu Cronet z Chromium Projects, která obsahuje originální verzi protokolu – gQUIC. Tato implementace je také neustále vylepšována, aby odpovídala posledním specifikacím IETF.

Nejprve jsme integrovali Cronet do našich aplikací pro Android, abychom přidali podporu QUIC. Integrace byla provedena tak, aby se minimalizovaly náklady na migraci. Místo úplné výměny starého síťového zásobníku, který používal knihovnu OkHttp, jsme integrovali Cronet POD rámcem OkHttp API. Tímto způsobem jsme se vyhnuli změnám v našich síťových voláních (které využívají Retrofit) na úrovni API.

Podobně jako u přístupu k zařízení Android jsme implementovali Cronet do aplikací Uber na iOS tím, že jsme zachytávali HTTP provoz ze síťových API, pomocí NSURLProtocol. Tato abstrakce poskytnutá iOS Foundation zpracovává specifická URL pro protokoly a zajišťuje, že můžeme integrovat Cronet do našich aplikací pro iOS bez významných nákladů na migraci.

Ukončení QUIC na vyrovnávacích serverech Google Cloud

Na straně backendu je ukončení QUIC zajištěno infrastrukturou vyrovnávání zatížení Google Cloud, která používá alt-svc hlavičky v odpovědích pro podporu QUIC. Obecně přidává vyrovnávač zatížení k každému HTTP požadavku hlavičku alt-svc, která validate podporu QUIC pro doménu. Když klient Cronet obdrží HTTP odpověď s touto hlavičkou, používá QUIC pro další HTTP požadavky na tuto doménu. Jakmile vyrovnávač dokončí QUIC, naše infrastruktura jasně odesílá tuto akci přes HTTP2/TCP do našich datových center.

Výkon: výsledky

Vydávaný výkon je hlavním důvodem našeho hledání nejlepšího protokolu. Nejdříve jsme vytvořili stanoviště s emulací sítě, abychom zjistili, jak se QUIC bude chovat při různých síťových profilech. Pro testování QUIC v reálných sítích jsme prováděli experimenty, projížděli New Delhi a používali emulovaný síťový provoz, velmi podobný HTTP voláním v aplikaci cestujícího.

Experiment 1

Inventář pro experiment:

  • testovací zařízení na Android s okruhy OkHttp a Cronet, abychom zajistili, že směrujeme HTTPS provoz přes TCP a QUIC;
  • server emulace založený na Javě, který posílá homogenní HTTPS hlavičky v odpovědích a zatěžuje klientská zařízení, aby od nich přijímal požadavky;
  • cloudové proxy, které se fyzicky nacházejí blízko Indie, aby dokončili TCP a QUIC spojení. Zatímco pro dokončení TCP jsme použili reverzní proxy na NGINX, bylo obtížné najít open-source reverzní proxy pro QUIC. Reverzní proxy pro QUIC jsme si vytvořili sami, pomocí základního stacku QUIC z Chromium a publikovali jehož jsme začlenili do Chromia jako open-source.

Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonuProtokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu
Obrázek 6. Testovací sestava pro TCP vs QUIC se skládala z Android zařízení s OkHttp a Cronet, cloudových proxy pro dokončení spojení a serveru emulace.

Experiment 2

Když Google zpřístupnil QUIC prostřednictvím Google Cloud Load Balancing, použili jsme stejný inventář, ale s jednou modifikací: místo NGINX jsme vzali google balancer pro dokončení TCP a QUIC spojení od zařízení a také pro směrování HTTPS provozu na server emulace. Vyrovnávače jsou rozloženy po celém světě, ale používají nejbližší PoP server (děkujeme geolokaci).

Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu
Obrázek 7. Ve druhém experimentu jsme chtěli porovnat latenci dokončení TCP a QUIC: pomocí Google Cloudu a pomocí naší cloudové proxy.

V konečném důsledku nás čekalo několik odhalení:

  • ukončení přes PoP zlepšilo výkon TCP. Protože vyvažovače ukončují TCP připojení blíže k uživatelům a jsou skvěle optimalizované, to snižuje RTT, což zlepšuje výkon TCP. A přestože to mělo menší dopad na QUIC, stále překonalo TCP z hlediska snižování prodlev (o 10–30 procent).
  • prodlevy ovlivňují síťové skoky (hops). I když byl náš QUIC proxy dále od zařízení (latence přibližně o 50 ms vyšší) než Googlovy vyvažovače, dosahoval podobného výkonu – 15% snížení latence oproti 20% snížení v 99. percentilu u TCP. To naznačuje, že přechod na poslední míli je úzké hrdlo (bottleneck) v síťovém výkonu.

Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonuProtokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu
Obrázek 8. Výsledky dvou experimentů ukazují, že QUIC výrazně překonává TCP.

Kontrolní provoz

Inspirováni experimenty jsme implementovali podporu QUIC do našich aplikací pro Android a iOS. Provedli jsme A/B testování, abychom zjistili vliv QUIC ve městech, kde Uber působí. Celkově jsme zaznamenali významné snížení prodlev v různých regionech, mobilních operátorech a typech sítí.

Na níže uvedených grafech jsou zobrazeny procentuální zlepšení prodlev (95. a 99. percentily) podle makroregionů a různých typů sítí – LTE, 3G, 2G.
Protokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonuProtokol QUIC v akci: jak ho implementoval Uber pro optimalizaci výkonu
Obrázek 9. V bojových testech QUIC překonal TCP z hlediska latence.

Jen vpřed

Snad je to teprve začátek – nasazení QUIC do produkce přineslo úžasné možnosti pro zlepšení výkonu aplikací jak v stabilních, tak v nestabilních sítích, a to konkrétně:

Zvýšení pokrytí

Analýzou výkonu protokolu na skutečném provozu jsme zjistili, že přibližně 80 % relací úspěšně používalo QUIC pro všechny požadavky, zatímco 15 % relací používalo kombinaci QUIC a TCP. Předpokládáme, že tato kombinace vznikla, protože knihovna Cronet přepíná zpět na TCP při timeoutu, protože není schopna rozlišit skutečné UDP selhání a špatné podmínky sítě. Nyní hledáme řešení tohoto problému, protože pracujeme na dalším zavedení QUIC.

Optimalizace QUIC

Provoz z mobilních aplikací je citlivý na zpoždění, nikoli na šířku pásma. Naše aplikace se převážně používají v mobilních sítích. Na základě experimentů stále existují značná zpoždění, i když používáme proxy pro dokončení TCP a QUIC blízko uživatelům. Aktivně hledáme způsoby, jak zlepšit řízení přetížení a zefektivnit QUIC algoritmy pro obnovu ztrát.

S těmito a dalšími vylepšeními plánujeme zlepšit uživatelskou zkušenost bez ohledu na síť a region, čímž učiníme pohodlnější a bezproblémový přenos balíčků dostupným po celém světě.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster