OpenVPN over TCP: rto_min løser ikke blokeringen ved køens begyndelse
En ydre bytestrøm leverer i rækkefølge, så ét manglende segment kan sætte hvert indre flow på pause. En længere indre timer ændrer et ur, ikke den begrænsning.
En interaktiv shell over tunnelen fryser i flere sekunder, mens en filkopiering kører, og fortsætter derefter, som om intet var sket. Downloadet er det eneste med et problem, alligevel venter shellen også, og begge kommer sig i samme øjeblik. Det mønster er signaturen på én pålidelig strøm, der bærer mange samtaler, og det overlever næsten enhver justering, som folk prøver først.
Symptomet er værd at læse omhyggeligt, fordi det peger på en mekanisme og ikke på en indstilling: pausen er delt, så årsagen er delt, og det delte objekt er den ydre forbindelse. Alt andet i loggen ser normalt ud, mens det sker.
Symptomet: alt holder pause på én gang
To indre forbindelser, der går i stå sammen, er ledetråden. Et langsomt download og en langsom shell er separate TCP-samtaler med separate sekvensnumre og separat overbelastningstilstand, så en fejl i den ene bør ikke røre den anden. Når de holder pause i takt, er der noget over dem, som ordner deres bytes.
Det noget er tunnelens transport. I TCP-tilstand skriver OpenVPN de indkapslede pakker i én TCP-forbindelse til peeren, og TCP's kontrakt er levering i rækkefølge af én enkelt bytestrøm. Senere bytes gives ikke til applikationen før de manglende, uanset hvilken indre samtale de hører til.
Læg mærke til, hvad symptomet ikke siger. Det siger ikke, at vejen er brudt, at serveren er overbelastet, eller at chifferet er langsomt. De giver andre former: jævnt lav gennemstrømning, tidsgrænser eller fejl, der rammer én retning. En delt pause, der slutter, når et tabt segment sendes igen, er netop en ordningseffekt.
Én ydre bytestrøm, mange indre samtaler
Forestil dig tunnelen, der bærer et download og en shell på samme tid. Et segment af den ydre forbindelse går tabt. De følgende segmenter kan nå den modtagende vært, og den modtagende TCP-stak bekræfter dem, men den kan ikke levere dem opad, før hullet er fyldt. OpenVPN har derfor intet at læse for shellen, selv om shellens egne bytes ankom for længe siden.
Det er blokering ved køens begyndelse inde i én forbindelse, og det kræver ikke, at de to applikationer deler en indre forbindelse. De deler den ydre, og det er nok.
Andenordenseffekten gør det værre. En indre afsender, der ikke ser bekræftelser, kan gensende data, som det ydre lag allerede forsøger at levere. Den gensendelse bliver ekstra tunneltrafik på en vej, der netop har bevist, at den kan tabe segmenter, så genopretningsarbejdet konkurrerer med den genopretning, der betyder noget.
Intet af dette garanterer et sammenbrud. På en ren vej med korte rundture og rummelige køer kan arrangementet være helt brugbart i årevis. Fejlen viser sig, når tab, forsinkelse og kødybde falder sammen, og derfor klumper rapporterne sig om overbelastede uplinks og mobile links i stedet for om velforsynede kontorer.
Hvorfor en længere indre timer ikke kan hjælpe
At hæve den mindste gensendelsestimeout på en rute med rto_min udskyder timerbaseret gensendelse for lokalt genereret TCP-trafik, der bruger ruten. Det er en rigtig knap med en rigtig effekt, og den angriber andenordensproblemet i stedet for det første.
ip route show
ip route show cache 2>/dev/null | head
ss -tin dst 10.70.0.1
Det, den ikke kan, er at frigive ydre bytes ude af rækkefølge, genoprette det manglende segment hurtigere eller få fjernserverens applikation til at bruge samme timer. Den modtagende stak leverer stadig i rækkefølge, og afsenderen i den anden ende bruger stadig sine egne rundtursmålinger.
Den slår heller ikke alle andre mekanismer til tabgenopretning fra. Hvor ægte tab kræver timerbaseret genopretning, får et større minimum applikationen til at vente længere, før den handler, hvilket er det modsatte af, hvad en latensfølsom session har brug for.
Et fast gulv på tolv sekunder dukker op i råd om emnet, som om en TCP-tunnels eksistens forudsatte det. Gensendelsestimeren, der er beskrevet i RFC 6298, udledes af målt rundtur med eksponentiel backoff, så et konstant gulv er et policyvalg for en bestemt vej og ikke et protokolkrav. Anvendt bredt skjuler det symptomet, mens det ændrer genopretningen for hvert flow, ruten dækker.
Hvad tcp-nodelay gør og ikke gør
Tunnelindstillingen, der slår Nagle-lignende buffering fra på transportsocket, har et snævert formål: den forhindrer små skrivninger i at vente på mere data før afsendelse. Det hjælper interaktiv trafik med at undgå en ekstra forsinkelse på en ellers sund vej.
Den gør ikke transporten uordnet, og den forkorter ikke genopretningen efter et tabt segment. En shell, der holder pause for en gensendelsestimeout, holder stadig pause med indstillingen slået til, fordi indstillingen aldrig rørte ordensreglen.
Det er let at forveksle de to, fordi begge beskrives som latensrettelser. Den ene fjerner en kunstig ventetid, som bufferingen indførte, den anden ville kræve at ændre, hvad transporten garanterer, og det gør ingen socket-indstilling.
Sådan sammenligner man transporter retfærdigt
Hvis operatøren tillader det, og begge tjenester findes, sammenlign en UDP-tjeneste og en TCP-tjeneste med samme arbejdsbyrde over samme adgangsvej til samme server. At skifte land, udbyder eller servergeneration mellem de to tests indfører en variabel, der vil dominere resultatet.
Hold øje med den delte pause i stedet for et gennemstrømningstal. Flere indre applikationer, der går i stå sammen under ydre tab, er den observation, der identificerer blokering ved køens begyndelse; et enkelt lavere hastighedstal gør det ikke.
Autoriserede optagelser på tunnelinterfacet og på det fysiske interface skiller de to lag rent, fordi indre og ydre gensendelser hører til forskellige forbindelser med forskellige sekvensrum. At se indre gensendelser, mens den ydre strøm viser et hul, er det direkte bevis.
At skifte til UDP fjerner den ekstra pålidelige strøm og lader indre TCP klare sin egen genopretning. Det lover ikke nul tab eller lav latens, og et mættet uplink, overdimensionerede køer eller et MTU-problem skal stadig rettes. Trafik uden for tunnelen holdes aldrig tilbage bag tunnelens sekvenshul, selv om den stadig kan lide, når begge veje deler et overbelastet link, og den delte flaskehals fortjener sin egen undersøgelse i stedet for at blive foldet ind i denne.