Zastoji OpenVPN preko TCP-a: rto_min ne rješava blokiranje na čelu reda
Vanjski bajtovni tok dostavlja po redu, pa jedan nedostajući segment može zaustaviti svaki unutrašnji tok. Duži unutrašnji tajmer mijenja sat, ne to ograničenje.
Interaktivna ljuska preko tunela zamrzne se nekoliko sekundi dok traje kopiranje datoteke, a zatim se nastavi kao da se ništa nije dogodilo. Preuzimanje je jedino što ima problem, ali i ljuska čeka, i oboje se oporave u istom trenutku. Taj obrazac je potpis jednog pouzdanog toka koji nosi mnoge razgovore, i preživljava gotovo svaku promjenu podešavanja koju ljudi prvo probaju.
Simptom vrijedi pažljivo pročitati jer upućuje na mehanizam, a ne na postavku: pauza je zajednička, pa je i uzrok zajednički, a zajednički objekt je vanjska veza. Sve ostalo u zapisniku izgleda normalno dok se to događa.
Simptom: sve stane odjednom
Dvije unutrašnje veze koje zapnu zajedno su trag. Sporo preuzimanje i spora ljuska odvojeni su TCP razgovori s odvojenim rednim brojevima i odvojenim stanjem zagušenja, pa kvar u jednoj ne bi trebao dotaknuti drugu. Kad zastanu u korak, nešto iznad njih poreda njihove bajtove.
To nešto je transport tunela. U TCP načinu OpenVPN upisuje inkapsulirane pakete u jednu TCP vezu prema partneru, a TCP ugovor je dostava jednog bajtovnog toka po redu. Kasniji bajtovi ne predaju se aplikaciji prije nedostajućih, bez obzira kojem unutrašnjem razgovoru pripadaju.
Obratite pažnju na ono što simptom ne govori. Ne kaže da je put pokvaren, da je server preopterećen ili da je šifra spora. To daje drugačije oblike: ujednačeno nisku propusnost, isteke vremena ili kvarove koji pogađaju jedan smjer. Zajednička pauza koja završi kad se jedan izgubljeni segment ponovno pošalje upravo je efekt redanja.
Jedan vanjski bajtovni tok, mnogo unutrašnjih razgovora
Zamislite tunel koji istovremeno nosi preuzimanje i ljusku. Segment vanjske veze se izgubi. Sljedeći segmenti mogu stići na prijemni host, a prijemni TCP stek će ih potvrditi, ali ih ne može predati prema gore dok se praznina ne popuni. OpenVPN zato nema šta čitati za ljusku, iako su vlastiti bajtovi ljuske stigli davno.
To je blokiranje na čelu reda unutar jedne veze, i ne zahtijeva da dvije aplikacije dijele unutrašnju vezu. Dijele vanjsku, što je dovoljno.
Efekt drugog reda pogoršava stvar. Unutrašnji pošiljalac koji ne vidi potvrdu može ponovno poslati podatke koje vanjski sloj već pokušava dostaviti. To ponovno slanje postaje dodatni promet kroz tunel na putu koji je upravo dokazao da može gubiti segmente, pa se rad na oporavku takmiči s oporavkom koji je bitan.
Ništa od ovoga ne garantuje slom. Na čistom putu s kratkim povratnim vremenima i izdašnim redovima, raspored može godinama biti potpuno upotrebljiv. Kvar se pojavljuje kad se gubitak, kašnjenje i dubina reda poklope, zato se izvještaji grupišu oko zagušenih uzlaznih veza i mobilnih linkova, a ne oko dobro opremljenih ureda.
Zašto duži unutrašnji tajmer ne može pomoći
Podizanje minimalnog isteka za ponovno slanje na ruti, s rto_min, odgađa ponovno slanje po tajmeru za lokalno generisan TCP promet koji koristi tu rutu. To je stvarna poluga sa stvarnim efektom, i rješava problem drugog reda, a ne prvog.
ip route show
ip route show cache 2>/dev/null | head
ss -tin dst 10.70.0.1
Ono što ne može jest osloboditi vanjske bajtove van reda, oporaviti nedostajući segment brže ili natjerati udaljeni aplikacijski server da usvoji isti tajmer. Prijemni stek i dalje dostavlja po redu, a pošiljalac na drugom kraju i dalje koristi svoja mjerenja povratnog vremena.
Također ne isključuje svaki drugi mehanizam oporavka od gubitka. Gdje pravi gubitak zahtijeva oporavak po tajmeru, veći minimum tjera aplikaciju da čeka duže prije nego što djeluje, što je suprotno onome što treba sesiji osjetljivoj na latenciju.
Fiksni donji prag od dvanaest sekundi pojavljuje se u savjetima o ovoj temi kao da ga postojanje TCP tunela podrazumijeva. Tajmer ponovnog slanja opisan u RFC 6298 izvodi se iz izmjerenog povratnog vremena s eksponencijalnim vraćanjem, pa je stalni prag izbor politike za određenu rutu, a ne zahtjev protokola. Primijenjen široko, skriva simptom dok mijenja oporavak za svaki tok koji ta ruta pokriva.
Šta tcp-nodelay radi, a šta ne radi
Opcija tunela koja isključuje baferovanje u Nagle stilu na transportnom socketu ima usku svrhu: sprječava male upise da čekaju više podataka prije slanja. To pomaže interaktivnom prometu da izbjegne dodatno kašnjenje na inače zdravom putu.
Ne pretvara transport u neuređeni i ne skraćuje oporavak nakon izgubljenog segmenta. Ljuska koja stane zbog isteka za ponovno slanje i dalje će stati s uključenom opcijom, jer opcija nikad nije dotakla pravilo redanja.
Lako je pobrkati to dvoje jer se oboje opisuju kao popravke latencije. Jedno uklanja umjetno čekanje koje uvodi baferovanje; drugo bi zahtijevalo mijenjanje onoga što transport garantuje, a to nijedna socket opcija ne čini.
Kako pošteno uporediti transporte
Ako operater dopušta i obje usluge postoje, uporedite UDP uslugu i TCP uslugu s istim opterećenjem preko istog pristupnog puta do istog servera. Promjena zemlje, provajdera ili generacije servera između dva testa uvodi varijablu koja će dominirati rezultatom.
Pazite na zajedničku pauzu, a ne na broj propusnosti. Nekoliko unutrašnjih aplikacija koje zapnu zajedno tokom vanjskog gubitka zapažanje je koje prepoznaje blokiranje na čelu reda; jedan niži broj testa brzine to ne čini.
Ovlaštena snimanja na interfejsu tunela i na fizičkom interfejsu čisto razdvajaju dva sloja, jer unutrašnja i vanjska ponovna slanja pripadaju različitim vezama s različitim prostorima rednih brojeva. Vidjeti unutrašnja ponovna slanja dok vanjski tok pokazuje prazninu direktan je dokaz.
Prelazak na UDP uklanja dodatni pouzdani tok i ostavlja unutrašnjem TCP-u da radi vlastiti oporavak. Ne obećava nula gubitaka ni nisku latenciju, a zasićena uzlazna veza, preveliki redovi ili MTU problem i dalje će trebati popravku. Promet izvan tunela nikad se ne zadržava iza praznine u redoslijedu tunela, iako može trpjeti kad oba puta dijele jednu zagušenu vezu, a to zajedničko grlo zaslužuje vlastitu istragu umjesto da se pripoji ovoj.