OpenVPN преко TCP-а: rto_min не решава блокаду на челу реда
Спољни ток бајтова испоручује по реду, па један сегмент који недостаје може зауставити сваки унутрашњи ток. Дужи унутрашњи тајмер мења сат, не то ограничење.
Интерактивни shell преко тунела замрзне на неколико секунди док траје копирање датотеке, а затим настави као да се ништа није догодило. Проблем има само преузимање, али и shell чека, и обоје се опорављају у истом тренутку. Тај образац је потпис једног поузданог тока који носи много разговора и преживљава скоро свако подешавање које људи прво пробају.
Симптом вреди пажљиво прочитати јер указује на механизам, а не на подешавање: пауза је заједничка, па је и узрок заједнички, а заједнички објекат је спољна веза. Све остало у дневнику изгледа нормално док се то дешава.
Симптом: све се зауставља истовремено
Две унутрашње везе које се заглаве заједно су траг. Споро преузимање и спор shell су одвојени TCP разговори са одвојеним редним бројевима и одвојеним стањем загушења, па грешка у једном не би требало да дотакне други. Када се зауставе у истом ритму, нешто изнад њих уређује њихове бајтове.
То нешто је транспорт тунела. У TCP режиму OpenVPN уписује инкапсулиране пакете у једну TCP везу ка партнеру, а уговор TCP-а је испорука по реду једног јединог тока бајтова. Каснији бајтови се не предају апликацији пре недостајућих, без обзира којем унутрашњем разговору припадају.
Обратите пажњу на то шта симптом не каже. Не каже да је путања покварена, да је сервер преоптерећен или да је шифровање споро. Они дају другачије облике: равномерно низак проток, истеке времена или отказе који погађају један смер. Заједничка пауза која се завршава када се изгубљени сегмент поново пошаље је управо ефекат уређења.
Један спољни ток бајтова, много унутрашњих разговора
Замислите тунел који истовремено носи преузимање и shell. Један сегмент спољне везе се губи. Следећи сегменти могу стићи до пријемног домаћина, и пријемни TCP стек ће их потврдити, али не може их предати навише док се празнина не попуни. Зато OpenVPN нема шта да чита за shell, иако су бајтови самог shell-а стигли давно.
Ово је блокада на челу реда унутар једне везе и не захтева да две апликације деле унутрашњу везу. Оне деле спољну, и то је довољно.
Ефекат другог реда то погоршава. Унутрашњи пошиљалац који не види потврде може поново послати податке које спољни слој већ покушава да испоручи. То поновно слање постаје додатни тунелски саобраћај на путањи која је управо доказала да може да губи сегменте, па се рад на опоравку такмичи са опоравком који је важан.
Ништа од овога не гарантује колапс. На чистој путањи са кратким повратним временима и издашним редовима, такав распоред може годинама бити потпуно употребљив. Отказ се појављује када се губитак, кашњење и дубина реда поклопе, и зато се извештаји гомилају око закрчених узлазних веза и мобилних веза, а не око добро опремљених канцеларија.
Зашто дужи унутрашњи тајмер не може да помогне
Подизање најмањег времена поновног слања на путањи помоћу rto_min одлаже поновно слање засновано на тајмеру за локално генерисан TCP саобраћај који користи ту путању. То је прави дугме са правим ефектом и бави се проблемом другог реда уместо првог.
ip route show
ip route show cache 2>/dev/null | head
ss -tin dst 10.70.0.1
Оно што не може је да пусти спољне бајтове ван реда, опорави сегмент који недостаје брже или натера удаљени сервер апликације да усвоји исти тајмер. Пријемни стек и даље испоручује по реду, а пошиљалац на даљем крају и даље користи своја мерења повратног времена.
Такође не искључује све остале механизме опоравка од губитка. Тамо где прави губитак захтева опоравак заснован на тајмеру, већи минимум тера апликацију да чека дуже пре него што делује, што је супротно од онога што је потребно сесији осетљивој на кашњење.
Фиксни минимум од дванаест секунди појављује се у саветима о овој теми као да постојање TCP тунела то подразумева. Тајмер поновног слања описан у RFC 6298 изводи се из измереног повратног времена са експоненцијалним узмаком, па је константан минимум избор политике за одређену путању, а не захтев протокола. Примењен широко, он скрива симптом док истовремено мења опоравак за сваки ток који та путања покрива.
Шта tcp-nodelay ради, а шта не
Опција тунела која искључује баферовање у стилу Nagle на транспортном сокету има уску сврху: спречава мале уписe да чекају више података пре слања. То помаже интерактивном саобраћају да избегне додатно кашњење на иначе здравој путањи.
Она не чини транспорт неуређеним и не скраћује опоравак после изгубљеног сегмента. Shell који се заустави због истека времена поновног слања зауставиће се и са укљученом опцијом, јер опција никада није дотакла правило реда.
Лако је заменити њих двоје јер се обоје описују као поправке кашњења. Једно уклања вештачко чекање које уводи баферовање, друго би захтевало промену онога што транспорт гарантује, а то не чини ниједна опција сокета.
Како поштено упоредити транспорте
Ако оператер дозвољава и обе услуге постоје, упоредите UDP услугу и TCP услугу са истим оптерећењем по истој приступној путањи ка истом серверу. Промена земље, добављача или генерације сервера између два теста уводи променљиву која ће доминирати резултатом.
Гледајте заједничку паузу, а не број протока. Неколико унутрашњих апликација које се заглаве заједно током спољног губитка је запажање које идентификује блокаду на челу реда; један нижи број теста брзине то не чини.
Овлашћени снимци на интерфејсу тунела и на физичком интерфејсу чисто раздвајају два слоја, јер унутрашња и спољна поновна слања припадају различитим везама са различитим редним просторима. Видети унутрашња поновна слања док спољни ток показује празнину је директан доказ.
Прелазак на UDP уклања додатни поуздани ток и оставља унутрашњем TCP-у његов сопствени опоравак. Не обећава нулти губитак или ниско кашњење, а засићена узлазна веза, превелики редови или проблем са MTU ће и даље морати да се реше. Саобраћај изван тунела никада се не задржава иза редне празнине тунела, иако и даље може да трпи када обе путање деле једну закрчену везу, а то заједничко грло заслужује сопствену истрагу уместо да буде уклопљено у ову.