Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța

Protocolul QUIC este extrem de interesant de urmărit, așa că ne place să scriem despre el. Însă, dacă publicațiile anterioare despre QUIC au avut mai mult un caracter istoric (dacă doriți, local), iar aspectele tehnice, astăzi suntem încântați să publicăm o traducere de altă natură – va fi vorba despre aplicarea reală a protocolului în 2019. Și nu este vorba despre o infrastructură mică, bazată într-un garaj imaginar, ci despre Uber, care operează aproape în întreaga lume. Cum au ajuns inginerii companiei la decizia de a utiliza QUIC în producție, cum au desfășurat teste și ce au observat după implementarea în producție – în continuare.

Imaginile sunt clicabile. Lectură plăcută!

Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța

Uber – are un impact global, adică 600 de orașe în care aplicația se bazează complet pe internet mobil de la mai mult de 4500 de operatori de telefonie mobilă. Utilizatorii se așteaptă ca aplicația să funcționeze nu doar rapid, ci în timp real – pentru a asigura acest lucru, aplicația Uber are nevoie de latențe scăzute și o conexiune foarte fiabilă. Din păcate, stiva HTTP/2 se descurcă slab în rețelele wireless dinamice și predispose la pierderi. Am realizat că, în acest caz, performanța scăzută este direct legată de implementările TCP din nucleele sistemelor de operare.

Pentru a rezolva problema, am aplicat QUIC, un protocol modern cu multiplexare de canale, care ne oferă mai mult control asupra performanței protocolului de transport. În prezent, grupul de lucru IETF standardizează QUIC ca HTTP/3.

După teste detaliate, am ajuns la concluzia că implementarea QUIC în aplicația noastră va reduce latențele „de coadă” în comparație cu TCP. Am observat o reducere în intervalul 10-30% pentru traficul HTTPS în cazul aplicațiilor de șoferi și pasageri. De asemenea, QUIC ne-a oferit control complet asupra pachetelor utilizatorilor.

În acest articol, împărtășim experiența noastră de optimizare a TCP pentru aplicațiile Uber folosind o stivă care suportă QUIC.

Ultimul cuvânt al tehnicii: TCP

Astăzi, TCP este cel mai utilizat protocol de transport pentru livrarea traficului HTTPS pe internet. TCP asigură un flux de biți fiabil, făcând față astfel suprasarcinilor de rețea și pierderilor la nivel de canal. Utilizarea extinsă a TCP pentru traficul HTTPS se explică prin omniprezența acestuia (aproape fiecare sistem de operare include TCP), disponibilitatea sa pe majoritatea infrastructurii (de exemplu, pe echipamentele de echilibrare a încărcării, proxi HTTPS și CDN) și funcționalitatea „la pachet” care este disponibilă aproape pe toate platformele și rețelele.

Cei mai mulți utilizatori utilizează aplicația noastră în mișcare, iar întârzierile „de coadă” ale TCP au fost departe de cerințele traficului nostru HTTPS în timp real. Cu alte cuvinte, acest lucru a fost întâmpinat de utilizatori din întreaga lume – întârzierile din marile orașe sunt reflectate în Figura 1:

Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța
Figura 1. Magnitudinea întârzierilor „de coadă” variază în principalele orașe în care este prezent Uber.

Deși întârzierile din rețelele indiene și braziliene au fost mai mari decât în SUA și Regatul Unit, întârzierile de coadă sunt semnificativ mai mari decât întârzierile medii. Și la fel este și în cazul SUA și Regatului Unit.

Performanța TCP pe wireless

TCP a fost creat pentru rețele cu fir, făcând astfel accent pe conexiuni bine predictibile. Totuși, rețelele wireless au propriile lor particularități și dificultăți. În primul rând, rețelele wireless sunt sensibile la pierderi din cauza interferențelor și a atenuării semnalului. De exemplu, rețelele Wi-Fi sunt sensibile la microunde, bluetooth și alte unde radio. Rețelele mobile suferă de pierderi de semnal (pierderea căii) din cauza reflecției/absorbției semnalului de către obiecte și clădiri, precum și de la interferențe provenite de la turnurile celulare vecine.Acest lucru duce la întârzieri circulare mai semnificative (în raport de 4-10 ori) și diverse întârzieri de rountrip (RTT) și pierderi de pachete în comparație cu o conexiune prin fir.

Pentru a face față fluctuațiilor lățimii de bandă și pierderilor, rețelele mobile folosesc de obicei buffere mari pentru vârfurile de trafic. Acest lucru poate duce la întârzieri excesive, ceea ce înseamnă întârzieri mai mari. Foarte des, TCP interpretează această întârzire ca o pierdere din cauza unui timeout crescut, astfel încât TCP tinde să retransmită și prin urmare să umple bufferul. Această problemă este cunoscută sub denumirea de bufferbloat, (supra-bufferizarea rețelei, umflarea bufferului), și aceasta este o problemă foarte serioasă. internetului modern.

În cele din urmă, performanța rețelei mobile variază în funcție de operatorul de telecomunicații, regiune și timp. În Figura 2, am adunat întârzierile mediane ale traficului HTTPS pe celule în intervalul de 2 kilometri. Datele sunt colectate pentru doi dintre cei mai mari operatori de telefonie mobilă din Delhi, India. Așa cum se poate observa, performanța variază de la o celulă la alta. De asemenea, performanța unui operator diferă de performanța altuia. Aceasta este influențată de factori precum modelele de acces la rețea în funcție de timp și locație, mobilitatea utilizatorilor, precum și infrastructura de rețea, având în vedere densitatea turnurilor și raportul tipurilor de rețea (LTE, 3G etc.).

Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța
Figura 2. Întârzieri exemplificate pe un perimetru de 2 kilometri. Delhi, India.

De asemenea, performanța rețelelor mobile variază în timp. În Figura 3 este prezentată întârzierea mediană în funcție de zilele săptămânii. Am observat și diferențe la o scară mai mică – în cadrul unei singure zile și ore.

Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța
Figura 3. Întârzierile de tip tail pot varia semnificativ în zile diferite, dar în cadrul aceluiași operator.

Toate cele menționate mai sus conduc la faptul că performanța TCP este ineficientă în rețelele wireless. Totuși, înainte de a căuta alternative la TCP, dorim să clarificăm înțelegerea noastră asupra următoarelor puncte:

  • este TCP principalul vinovat pentru întârzierile de tip tail în aplicațiile noastre?
  • au rețelele moderne întârzieri circulare semnificative și diverse (RTT)?
  • care este impactul RTT și al pierderilor asupra performanței TCP?

Analiza performanței TCP

Pentru a înțelege cum am analizat performanța TCP, să ne reamintim pe scurt cum TCP transmite date de la emitător la receptor. La început, emitătorul stabilește o conexiune TCP, realizând un proces de trei pași. handshake: emitătorul trimite un pachet SYN, așteaptă un pachet SYN-ACK de la receptor, apoi trimite un pachet ACK. Pașii doi și trei sunt necesari pentru a stabili conexiunea TCP. Receptorul confirmă primirea fiecărui pachet (ACK) pentru a asigura livrarea fiabilă.

Dacă un pachet sau un ACK este pierdut, emitătorul retransmite după un timp de așteptare (RTO, timp de retransmisie). RTO este calculat dinamic, pe baza diverselor factori, de exemplu, pe baza întârzierii așteptate RTT între emitător și receptor.

Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța
Figura 4. Schimbul de pachete prin TCP/TLS include mecanisme de retransmisie.

Pentru a determina cum a funcționat TCP în aplicațiile noastre, am urmărit pachetele TCP folosind tcpdump pe parcursul unei săptămâni pe traficul de producție provenit de la serverele de frontieră indiene. Apoi am analizat conexiunile TCP folosind tcptrace. De asemenea, am creat o aplicație Android care trimite trafic emulat către un server de test, imitând cât mai bine traficul real. Smartphone-urile cu această aplicație au fost distribuite câtorva angajați care au colectat jurnale timp de câteva zile.

Rezultatele ambelor experimente au fost conforme între ele. Am observat întârzieri RTT ridicate; valorile de coadă erau aproape de 6 ori mai mari decât valoarea mediană; valoarea medie a întârzierilor era de peste 1 secundă. Multe conexiuni au avut pierderi, ceea ce a determinat TCP să retransmită 3,5% din toate pachetele. În zonele cu suprasarcină, cum ar fi aeroporturile și gările, am observat pierderi de 7%. Aceste rezultate pun sub semnul întrebării opinia comună că schemele avansate de retransmisie utilizate în rețelele celulare reduce semnificativ pierderile la nivel de transport. Mai jos sunt rezultatele testelor din aplicația-simulant: Metri de rețea

RTT, milisecunde [50%, 75%, 95%, 99%]
Valorile

Discrepanța RTT, secunde
[350, 425, 725, 2300]

În medie ~1,2 s
Pierderea pachetelor în conexiuni instabile

În medie ~3.5% (7% în zonele cu suprasarcină)
Aproape jumătate dintre aceste conexiuni au avut cel puțin o pierdere de pachete, majoritatea fiind pachete SYN și SYN-ACK. Cele mai multe implementări TCP utilizează o valoare RTO de 1 secundă pentru pachetele SYN, care crește exponential pentru pierderile ulterioare. Timpul de încărcare al aplicației poate crește deoarece TCP necesită mai mult timp pentru a stabili conexiuni.

În cazul pachetelor de date, valorile ridicate ale RTO reduc semnificativ utilizarea utilă a rețelei în condiții de pierderi temporare în rețelele wireless. Am descoperit că timpul mediu de retransmisie este de aproximativ 1 secundă, cu o întârziere de coadă de aproape 30 de secunde. Aceste întârzieri ridicate la nivel TCP cauzau timeout-uri HTTPS și solicitări repetate, ceea ce creștea și mai mult întârzierea și ineficiența rețelei.

În cazul pachetelor de date, valorile ridicate ale RTO reduc semnificativ utilizarea eficientă a rețelei în prezența pierderilor temporale în rețelele wireless. Am descoperit că timpul mediu de retransmisie este de aproximativ 1 secundă, cu o întârziere de aproape 30 de secunde. Astfel de întârzieri ridicate la nivel TCP au provocat timeout-uri HTTPS și cereri repetate, ceea ce a crescut și mai mult întârzierile și ineficiența rețelei.

În timp ce percentilul de 75% al RTT-urilor măsurate era în jur de 425 ms, percentilul de 75% pentru TCP era aproape 3 secunde. Aceasta sugerează că pierderile forțau TCP să efectueze 7-10 treceri pentru a transmite cu succes datele. Aceasta ar putea fi consecința unei estimări ineficiente a RTO-ului, incapabilitatea TCP de a reacționa rapid la pierderi. ultimelor pachete în fereastră și ineficienței algoritmului de control al congestionării, care nu face distincție între pierderile wireless și cele cauzate de congestionarea rețelei. Mai jos sunt rezultatele testelor de pierdere TCP:

Statistica pierderii pachetelor TCP
Valoare

Procentul de conexiuni cu cel puțin 1 pierdere de pachet
45%

Procentul de conexiuni cu pierderi în timpul stabilirii conexiunii
30%

Procentul de conexiuni cu pierderi în timpul transferului de date
76%

Distribuția întârzierilor în retransmisie, secunde [50%, 75%, 95%, 99%]
[1, 2.8, 15, 28]

Distribuția numărului de retransmisii pentru un pachet sau segment TCP
[1,3,6,7]

Aplicarea QUIC

Inițial proiectat de Google, QUIC este un protocol de transport modern multithread care funcționează deasupra UDP. În prezent, QUIC este în proces de standardizare (am menționat deja că există practic două versiuni ale QUIC, cei curioși pot accesa linkul – n.trad.). Așa cum se arată în Figura 5, QUIC este sub HTTP/3 (de fapt, HTTP/2 deasupra QUIC este HTTP/3, care este acum intens standardizat). Acesta înlocuiește parțial nivelurile HTTPS și TCP, folosind UDP pentru formarea pachetelor. QUIC suportă doar transferuri de date securizate, deoarece TLS este complet integrat în QUIC.

Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța
Figura 5: QUIC funcționează sub HTTP/3, înlocuind TLS, care anterior funcționa sub HTTP/2.

Mai jos, enumerăm motivele care ne-au convins să folosim QUIC pentru a îmbunătăți TCP:

  • 0-RTT stabilirea conexiunii. QUIC permite reutilizarea autorizărilor din conexiuni anterioare, reducând numărul de handshake-uri de securitate. În viitor, TLS1.3 va suporta 0-RTT, însă handshake-ul TCP în trei pași va rămâne obligatoriu.
  • depășirea blocajului HoL. HTTP/2 folosește o singură conexiune TCP pentru fiecare client pentru a îmbunătăți performanța, dar aceasta poate duce la blocarea HoL (head-of-line). QUIC simplifică multiplexarea și livrarea cererilor către aplicație independent una de alta.
  • gestionarea congestionării. QUIC se află la nivelul aplicațiilor, permițând actualizarea mai ușoară a principalului algoritm de transport, care gestionează trimiterea, bazându-se pe parametrii rețelei (numărul de pierderi sau RTT). Cele mai multe implementări TCP folosesc algoritmul CUBIC, care nu este optim pentru traficul sensibil la întârzieri. Algoritmi recent dezvoltați, precum BBR, modeleză mai precis rețeaua și optimizează întârzierile. QUIC permite utilizarea BBR și actualizarea acestui algoritm pe măsură ce se îmbunătățește.
  • recuperarea pierderilor. QUIC efectuează două TLP (tail loss probe) înainte ca RTO să se activeze – chiar și atunci când pierderile sunt foarte vizibile. Aceasta este diferită de implementările TCP. TLP retransmite în principal ultimul pachet (sau unul nou, dacă există), pentru a iniția o recuperare rapidă. Gestionarea întârzierilor finale este în special utilă pentru modul în care Uber operează în rețea, și anume pentru transferurile de date scurte, episodice și sensibile la întârzieri.
  • ACK optimizat. Deoarece fiecare pachet are un număr secvențial unic, nu apare problema distinguerii pachetelor la retransmitere. Pachetele ACK conțin, de asemenea, timpul necesar pentru procesarea pachetului și generarea ACK-ului pe partea clientului. Aceste caracteristici garantează că QUIC calculează RTT mai precis. ACK în QUIC suportă până la 256 de intervale NACK, ajutând expeditorul să fie mai rezistent la rearanjarea pachetelor și să utilizeze mai puțini biți în proces. ACK-ul selectiv (SACK) în TCP nu rezolvă această problemă în toate cazurile.
  • migrarea conexiunii. Conexiunile QUIC sunt identificate cu ajutorul unui ID de 64 de biți, astfel încât dacă clientul își schimbă adresele IP, se poate utiliza în continuare ID-ul vechii conexiuni pe noua adresă IP, fără întreruperi. Aceasta este o practică foarte comună pentru aplicațiile mobile, atunci când utilizatorul comută între conexiunile Wi-Fi și cele cellular.

Alternativele QUIC

Am analizat abordări alternative pentru a rezolva problema înainte de a alege QUIC.

În primul rând, am încercat să implementăm TPC PoPs (Puncte de Prezență), pentru a finaliza conexiunile TCP mai aproape de utilizatori. Practic, PoPs finalizează conexiunea TCP cu dispozitivele mobile mai aproape de rețeaua celulară și proxează traficul până la infrastructura originală. Finalizând TCP mai aproape, putem potențial reduce RTT-ul și putem fi siguri că TCP va reacționa mai activ la un mediu wireless dinamic. Totuși, experimentele noastre au arătat că, în mare parte, RTT-ul și pierderile vin din rețelele celulare, iar utilizarea PoPs nu oferă o îmbunătățire semnificativă a performanței.

De asemenea, ne-am îndreptat atenția către ajustarea parametrilor TCP. Configurarea stivei TCP pe serverele noastre de frontieră heterogene a fost dificilă, deoarece TCP are implementări incompatibile în diferite versiuni de OS. A fost greu de implementat și de testat diverse configurații de rețea. Ajustarea TCP direct pe dispozitivele mobile a fost imposibilă din cauza lipsei de privilegii. Și mai important, funcționalități precum conexiunile cu 0-RTT și predicția îmbunătățită a RTT-ului sunt esențiale pentru arhitectura protocolului și, prin urmare, nu se pot obține avantaje semnificative doar prin ajustarea TCP.

În cele din urmă, am evaluat câteva protocoale bazate pe UDP care abordează problemele în streaming-ul video – am dorit să aflăm dacă aceste protocoale ar putea să ne ajute în cazul nostru. Din păcate, le lipseau multe dintre setările de securitate, iar acestea necesitau o conexiune TCP suplimentară pentru metadate și informații de control.

Cercetările noastre au arătat că QUIC este aproape singurul protocol care poate ajuta la problema traficului pe Internet, luând în considerare atât securitatea cât și performanța.

Integrarea QUIC în platformă

Pentru a integra cu succes QUIC și a îmbunătăți performanța aplicației în condiții de conexiune slabă, am înlocuit vechea stivă (HTTP/2 deasupra TLS/TCP) cu protocolul QUIC. Am utilizat biblioteca de rețea Cronet din Chromium Projects, care conține versiunea originală, dezvoltată de Google, a protocolului – gQUIC. Această implementare este, de asemenea, îmbunătățită constant pentru a urma ultima specificație IETF.

Am integrat mai întâi Cronet în aplicațiile noastre Android pentru a adăuga suport pentru QUIC. Integrarea a fost realizată astfel încât să reducem la minimum costurile migrației. În loc să înlocuim complet vechiul stack de rețea care folosea biblioteca OkHttp, am integrat Cronet sub cadrul API-ului OkHttp. Realizând integrarea în acest mod, am evitat modificările în apelurile noastre de rețea (care utilizează Retrofit) la nivel de API.

Similar abordării pentru dispozitivele Android, am implementat Cronet în aplicațiile Uber pe iOS, interceptând traficul HTTP din API, utilizând NSURLProtocol. Această abstracție oferită de fundația iOS gestionează datele URL specifice protocolului și garantează că putem integra Cronet în aplicațiile noastre iOS fără costuri semnificative de migrare.

Finalizarea QUIC pe echilibratoarele de încărcare Google Cloud

Pe partea de backend, finalizarea QUIC este asigurată de infrastructura Google Cloud Load balancing, care utilizează alt-svc header-e în răspunsuri pentru a susține QUIC. În general, fiecare solicitare HTTP la echilibrator adaugă un header alt-svc și validează astfel suportul QUIC pentru domeniu. Când clientul Cronet primește un răspuns HTTP cu un astfel de header, el folosește QUIC pentru solicitările HTTP următoare către acest domeniu. Odată ce echilibratorul finalizează QUIC, infrastructura noastră trimite explicit această acțiune prin HTTP2/TCP către centrele noastre de date.

Performanță: rezultate

Performanța livrată este principala noastră motivație în căutarea celui mai bun protocol. Pentru început, am creat un stand cu simularea rețelei, pentru a descoperi cum se comportă QUIC în diverse profile de rețea. Pentru a verifica funcționarea QUIC în rețele reale, am desfășurat experimente călătorind prin New Delhi, folosind un trafic de rețea simulat foarte asemănător cu apelurile HTTP din aplicația pasagerului.

Experiment 1

Inventar pentru experiment:

  • dispozitive de test pe Android cu stack-uri OkHttp și Cronet, pentru a ne asigura că dirijăm traficul HTTPS pe TCP și QUIC în mod corespunzător;
  • un server de simulare bazat pe Java, care trimite header-e HTTPS omogene în răspunsuri și încarcă dispozitivele client pentru a primi solicitări de la acestea;
  • proxies în cloud, care sunt fizic situate aproape de India, pentru a finaliza conexiunile TCP și QUIC. În timp ce pentru finalizarea TCP am folosit un proxy invers pe NGINX, a fost greu să găsim un proxy invers open-source pentru QUIC. Am creat un proxy invers pentru QUIC noi înșine, utilizând stiva de bază QUIC din Chromium și au publicat l-am integrat în Chromium ca open-source.

Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanțaProtocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța
Figura 6. Setul mobil de teste TCP vs QUIC a fost format din dispozitive Android cu OkHttp și Cronet, proxy cloud pentru finalizarea conexiunilor și un server de emulare.

Experiment 2

Când Google a făcut disponibil QUIC prin Google Cloud Load Balancing, am folosit același inventar, dar cu o modificare: în loc de NGINX, am folosit load balancerele Google pentru a finaliza conexiunile TCP și QUIC de la dispozitive, dar și pentru a direcționa traficul HTTPS către serverul de emulare. Balancerele sunt distribuite la nivel global, dar folosesc serverul PoP cel mai apropiat de dispozitiv (mulțumită geolocației).

Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța
Figura 7. În al doilea experiment, am dorit să comparăm latența finalizării TCP și QUIC: folosind Google Cloud și utilizând proxy-ul nostru cloud.

În cele din urmă, ne-au așteptat câteva revelații:

  • finalizarea prin PoP a îmbunătățit performanța TCP. Deoarece load balancerele finalizează conexiunea TCP mai aproape de utilizatori și sunt foarte optimizate, acest lucru oferă RTT-uri mai mici, ceea ce îmbunătățește performanța TCP. Și deși a avut un impact mai mic asupra QUIC, acesta a depășit în continuare TCP în ceea ce privește reducerea latenței de final (cu 10-30 la sută).
  • la latențe influențează trecerile rețelei (hops). Deși proxy-ul nostru QUIC era mai departe de dispozitive (latență cu aproximativ 50 ms mai mare) decât load balancerele Google, acesta oferea o performanță similară – o reducere a latențelor de 15% comparativ cu o reducere de 20% în percentila de 99 la sută pentru TCP. Aceasta sugerează că trecerea pe ultima milă este un loc îngust (bottleneck) în funcționarea rețelei.

Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanțaProtocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța
Figura 8. Rezultatele celor două experimente arată că QUIC depășește semnificativ TCP.

Trafic operațional

Inspirat de experimente, am implementat suport QUIC în aplicațiile noastre Android și iOS. Am realizat teste A/B pentru a determina impactul QUIC în orașele în care este prezent Uber. În general, am observat o reducere semnificativă a latențelor de final din perspectiva regiunilor, operatorilor de telefonie și tipului de rețea.

Graficele de mai jos arată îmbunătățirile procentuale ale latențelor (95 și 99 percentile) pe macroregiuni și diferite tipuri de rețea – LTE, 3G, 2G.
Protocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanțaProtocolul QUIC în acțiune: cum l-a implementat Uber pentru a optimiza performanța
Figura 9. În testele operaționale, QUIC a depășit TCP în ceea ce privește latențele.

Numai înainte

Probabil că acesta este doar începutul – implementarea QUIC în producție a oferit oportunități uimitoare de îmbunătățire a performanței aplicațiilor atât în rețele stabile, cât și instabile, și anume:

Creșterea acoperirii

Analizând performanța protocolului pe trafic real, am observat că aproximativ 80% din sesiuni au utilizat cu succes QUIC pentru tuturor cereri, în timp ce 15% din sesiuni au folosit o combinație de QUIC și TCP. Presupunem că această combinație a apărut deoarece biblioteca Cronet trece înapoi la TCP din cauza timpilor de așteptare, deoarece nu poate distinge între eșecurile reale UDP și condițiile slabe ale rețelei. Acum căutăm o soluție pentru această problemă, în timp ce lucrăm la implementarea ulterioară a QUIC.

Optimizarea QUIC

Traficul din aplicațiile mobile este sensibil la întârzieri, dar nu la lățimea de bandă. De asemenea, aplicațiile noastre sunt utilizate predominant în rețele celulare. Bazându-ne pe experimente, întârzierile de coadă sunt încă mari, chiar și cu utilizarea de proxy-uri pentru finalizarea TCP și QUIC aproape de utilizatori. Căutăm activ modalități de a îmbunătăți gestionarea congestionării și de a spori eficiența algoritmilor QUIC de recuperare a pierderilor.

Cu aceste și alte îmbunătățiri, plănuim să îmbunătățim experiența utilizatorului, indiferent de rețea și regiune, făcând transportul de pachete convenabil și fără întreruperi mai accesibil la nivel global.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster