Ett interaktivt skal över tunneln fryser i flera sekunder medan en filkopiering körs, och fortsätter sedan som om ingenting hade hänt. Nedladdningen är det enda som har ett problem, ändå väntar skalet också, och båda återhämtar sig i samma ögonblick. Det mönstret är signaturen hos en enda tillförlitlig ström som bär många samtal, och det överlever nästan varje inställningsändring folk prövar först.

Symtomet är värt att läsa noggrant eftersom det pekar på en mekanism snarare än en inställning: pausen är delad, alltså är orsaken delad, och det delade objektet är den yttre anslutningen. Allt annat i loggen ser normalt ut medan det pågår.

Symtomet: allt pausar samtidigt

Två inre anslutningar som fastnar tillsammans är ledtråden. En långsam nedladdning och ett långsamt skal är separata TCP-samtal med separata sekvensnummer och separat överbelastningstillstånd, så ett fel i det ena borde inte röra det andra. När de pausar i takt är det något ovanför dem som ordnar deras byte.

Det där något är tunnelns transport. I TCP-läge skriver OpenVPN de inkapslade paketen i en enda TCP-anslutning till peern, och TCP:s kontrakt är leverans i ordning av en enda byteström. Senare byte lämnas inte till programmet före de saknade, oavsett vilket inre samtal de tillhör.

Lägg märke till vad symtomet inte säger. Det säger inte att vägen är trasig, att servern är överbelastad eller att chiffret är långsamt. De ger andra former: jämnt låg genomströmning, tidsgränser eller fel som bara drabbar en riktning. En delad paus som slutar när ett förlorat segment sänds om är specifikt en ordningseffekt.

En yttre byteström, många inre samtal

Tänk dig tunneln som bär en nedladdning och ett skal samtidigt. Ett segment i den yttre anslutningen går förlorat. Följande segment kan nå den mottagande värden, och den mottagande TCP-stacken bekräftar dem, men den kan inte leverera dem uppåt förrän luckan är fylld. OpenVPN har därför inget att läsa för skalet, trots att skalets egna byte kom för länge sedan.

Detta är blockering vid köns början inom en enda anslutning, och det kräver inte att de två programmen delar en inre anslutning. De delar den yttre, och det räcker.

Andra ordningens effekt gör det värre. En inre avsändare som inte ser någon bekräftelse kan sända om data som det yttre lagret redan försöker leverera. Den omsändningen blir extra tunneltrafik på en väg som just visat att den kan tappa segment, så återhämtningsarbetet konkurrerar med den återhämtning som spelar roll.

Inget av detta garanterar en kollaps. På en ren väg med korta tur-och-retur-tider och generösa köer kan arrangemanget vara fullt användbart i åratal. Felet visar sig när förlust, fördröjning och ködjup sammanfaller, och därför klumpar rapporterna ihop sig kring överbelastade upplänkar och mobila länkar i stället för kring välförsedda kontor.

Varför en längre inre timer inte kan hjälpa

Att höja den minsta omsändningstiden på en rutt med rto_min skjuter upp timerbaserad omsändning för lokalt genererad TCP-trafik som använder rutten. Det är en riktig ratt med en riktig effekt, och den tar sig an andra ordningens problem i stället för det första.

ip route show
ip route show cache 2>/dev/null | head
ss -tin dst 10.70.0.1

Vad den inte kan är att släppa yttre byte ur ordning, återställa det saknade segmentet snabbare eller få fjärrservern för programmet att anta samma timer. Den mottagande stacken levererar fortfarande i ordning, och avsändaren i andra änden använder fortfarande sina egna tur-och-retur-mätningar.

Den stänger inte heller av alla andra mekanismer för förluståterhämtning. Där verklig förlust kräver timerbaserad återhämtning låter ett större minimum programmet vänta längre innan det handlar, vilket är motsatsen till vad en latenskänslig session behöver.

Ett fast golv på tolv sekunder dyker upp i råd om ämnet som om en TCP-tunnels existens förutsatte det. Omsändningstimern som beskrivs i RFC 6298 härleds från uppmätt tur-och-retur-tid med exponentiell backoff, så ett konstant golv är ett policyval för en viss väg och inte ett protokollkrav. Tillämpat brett döljer det symtomet samtidigt som det ändrar återhämtningen för varje flöde som rutten omfattar.

Vad tcp-nodelay gör och inte gör

Tunnelalternativet som stänger av Nagle-liknande buffring på transportsocket har ett snävt syfte: det hindrar små skrivningar från att vänta på mer data före sändning. Det hjälper interaktiv trafik att undvika en extra fördröjning på en i övrigt frisk väg.

Det gör inte transporten oordnad, och det förkortar inte återhämtningen efter ett förlorat segment. Ett skal som pausar för en omsändningstidsgräns pausar fortfarande med alternativet påslaget, eftersom alternativet aldrig rörde ordningsregeln.

Det är lätt att blanda ihop de två eftersom båda beskrivs som latensfixar. Den ena tar bort en konstgjord väntan som buffringen inför, den andra skulle kräva att det transporten garanterar ändras, och det gör ingen socket-inställning.

Hur man jämför transporter rättvist

Om operatören tillåter det och båda tjänsterna finns, jämför en UDP-tjänst och en TCP-tjänst med samma arbetslast över samma åtkomstväg till samma server. Att byta land, leverantör eller servergeneration mellan de två testerna för in en variabel som kommer att dominera resultatet.

Titta efter den delade pausen i stället för en genomströmningssiffra. Flera inre program som fastnar tillsammans under yttre förlust är observationen som identifierar blockering vid köns början; en enda lägre hastighetssiffra gör det inte.

Auktoriserade fångster på tunnelgränssnittet och på det fysiska gränssnittet skiljer de två lagren rent, eftersom inre och yttre omsändningar tillhör olika anslutningar med olika sekvensutrymmen. Att se inre omsändningar medan den yttre strömmen visar en lucka är det direkta beviset.

Att byta till UDP tar bort den extra tillförlitliga strömmen och låter inre TCP göra sin egen återhämtning. Det lovar inte noll förluster eller låg latens, och en mättad upplänk, överdimensionerade köer eller ett MTU-problem måste fortfarande åtgärdas. Trafik utanför tunneln hålls aldrig kvar bakom tunnelns sekvenslucka, även om den fortfarande kan lida när båda vägarna delar en överbelastad länk, och den delade flaskhalsen förtjänar sin egen utredning i stället för att vikas in i denna.

Relaterade artiklar