Інтерактивна оболонка через тунель завмирає на кілька секунд, поки йде копіювання файлу, а потім продовжує роботу так, ніби нічого не сталося. Проблема є лише в завантаженні, але оболонка теж чекає, і обидві відновлюються в той самий момент. Цей шаблон — підпис одного надійного потоку, що несе безліч розмов, і він переживає майже будь-яке налаштування, яке люди пробують першим.

Варто читати симптом уважно, бо він указує на механізм, а не на параметр: пауза спільна, отже й причина спільна, а спільний об'єкт — зовнішнє з'єднання. Усе інше в журналі під час цього виглядає нормально.

Симптом: усе завмирає одночасно

Два внутрішні з'єднання, що застрягають разом, — ось підказка. Повільне завантаження і повільна оболонка — це окремі розмови TCP з окремими номерами послідовності й окремим станом перевантаження, тому збій в одному не повинен зачіпати інший. Коли вони завмирають синхронно, щось над ними впорядковує їхні байти.

Це щось — транспорт тунелю. У режимі TCP OpenVPN записує інкапсульовані пакети в одне TCP-з'єднання з вузлом, а контракт TCP — доставка по порядку єдиного потоку байтів. Пізніші байти не передаються застосунку раніше за відсутні, до якої б внутрішньої розмови вони не належали.

Зверніть увагу, чого симптом не каже. Він не каже, що шлях зламаний, що сервер перевантажений або що шифр повільний. Вони дають інші форми: рівномірно низьку пропускну здатність, тайм-аути або збої, що зачіпають один напрямок. Спільна пауза, яка закінчується, коли втрачений сегмент передається повторно, — це саме ефект порядку.

Один зовнішній потік байтів, безліч внутрішніх розмов

Уявіть, що тунель несе завантаження й оболонку одночасно. Один сегмент зовнішнього з'єднання губиться. Наступні сегменти можуть дійти до приймального вузла, і приймальний стек TCP підтвердить їх, але не зможе передати їх угору, поки розрив не заповнено. Тому OpenVPN нема чого читати для оболонки, хоча байти самої оболонки прийшли давно.

Це блокування на початку черги всередині одного з'єднання, і воно не вимагає, щоб два застосунки ділили внутрішнє з'єднання. Вони ділять зовнішнє, і цього достатньо.

Ефект другого порядку погіршує її. Внутрішній відправник, який не бачить підтверджень, може повторно передати дані, які зовнішній рівень уже намагається доставити. Ця повторна передача стає додатковим трафіком тунелю на шляху, що щойно довів, що може губити сегменти, тому робота з відновлення конкурує з відновленням, яке має значення.

Ніщо з цього не гарантує краху. На чистому шляху з короткими круговими затримками й щедрими чергами така схема може роками залишатися цілком робочою. Відмова з'являється, коли втрати, затримка й глибина черги збігаються, тому повідомлення групуються навколо перевантажених висхідних каналів і мобільних лінків, а не навколо добре забезпечених офісів.

Чому довший внутрішній таймер не може допомогти

Підвищення мінімального тайм-ауту повторної передачі на маршруті за допомогою 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 на транспортному сокеті, має вузьку мету: вона не дає дрібним записам чекати додаткових даних перед відправленням. Це допомагає інтерактивному трафіку уникнути зайвої затримки на інакше здоровому шляху.

Вона не робить транспорт невпорядкованим і не скорочує відновлення після втраченого сегмента. Оболонка, що завмирає на тайм-ауті повторної передачі, завмиратиме й з увімкненою опцією, бо опція ніколи не торкалася правила порядку.

Сплутати одне з одним легко, бо обидві описані як виправлення затримки. Одна прибирає штучне очікування, введене буферизацією, інша вимагала б змінити те, що гарантує транспорт, а цього не робить жодна опція сокета.

Як чесно порівнювати транспорти

Якщо оператор це дозволяє і обидві служби існують, порівняйте службу UDP і службу TCP з однаковим навантаженням тим самим шляхом доступу до того самого сервера. Зміна країни, провайдера або покоління сервера між двома тестами вводить змінну, яка домінуватиме в результаті.

Стежте за спільною паузою, а не за числом пропускної здатності. Кілька внутрішніх застосунків, що застрягають разом під час зовнішньої втрати, — це спостереження, яке виявляє блокування на початку черги; одна нижча цифра тесту швидкості цього не робить.

Дозволені захоплення на інтерфейсі тунелю і на фізичному інтерфейсі чисто розділяють два рівні, бо внутрішні й зовнішні повторні передачі належать різним з'єднанням з різними просторами послідовностей. Бачити внутрішні повторні передачі, поки зовнішній потік показує розрив, — це прямий доказ.

Перехід на UDP прибирає зайвий надійний потік і залишає внутрішньому TCP власне відновлення. Він не обіцяє нульових втрат чи низької затримки, і насичений висхідний канал, роздуті черги або проблема MTU все одно потребуватимуть виправлення. Трафік поза тунелем ніколи не затримується за розривом послідовності тунелю, хоча він усе ж може страждати, коли обидва шляхи ділять один перевантажений канал, і це спільне вузьке місце заслуговує окремого розслідування, а не зведення в це.

Схожі статті