Під час аналізу причин підвищеної затримки (Latency) у високошвидкісних зашифрованих тунелях інженери зазвичай звертають увагу на транзитні маршрути інтернету, нестабільність бездротового зв\x27язку або переповнення черг на зовнішніх маршрутизаторах. Проте в операційних системах Linux істотна частка затримки часто формується безпосередньо всередині локального ядра ще до того, як кадри потрапляють до фізичного чи віртуального мережевого адаптера. Це явище отримало назву локального буферблоту (Host Bufferbloat) і тривалий час призводило до втрати чуйності інтерактивних додатків під час активного завантаження файлів.
Щоб усунути багатомегабайтні черги в драйверах мережевих плат і зберегти граничну швидкість передачі даних, розробник ядра Linux Ерік Дюмазе (Eric Dumazet) створив архітектуру малих черг TCP (TCP Small Queues — TSQ). Встановивши динамічні обмеження обсягу переданих даних для кожного сокета між транспортним рівнем і підсистемою керування чергами (qdisc), механізм TSQ кардинально перетворив конвеєр вихідного трафіку. Розуміння цієї моделі є критично важливим для проєктування високоефективних VPN-тунелів та сервісів обробки трафіку.
Механізми виникнення Bufferbloat хоста до впровадження TSQ
До виходу версії ядра 3.6 стек TCP передавав дані вниз до мережевого обладнання настільки швидко, наскільки це дозволяло вікно перевантаження (snd_cwnd). Якщо буфер запису сокета містив вільне місце, ядро негайно упаковувало байти в структури sk_buff і відправляло їх безпосередньо до черг підсистеми Traffic Control.
Під час масового передавання файлів це призводило до накопичення сотень або навіть тисяч невідправлених пакетів у кільцевих буферах дескрипторів драйвера (TX Ring). Один швидкісний потік TCP міг легко накопичити від 2 до 8 мегабайтів даних у чергах пам\x27яті ядра, очікуючи на їх серіалізацію в мережевий кабель.
[ Запис програми Application Write ]
│
▼
[ Буфер сокета TCP Socket Buffer ] ──► Вікно cwnd дозволяє передачу
│
▼
[ Кільцевий буфер драйвера TX Ring ] ──► (Неконтрольоване накопичення мегабайтів)
│
▼
[ Фізичний адаптер PHY / Віртуальний TUN ]
Така некерована буферизація викликала три системні проблеми:
- Зростання часу кругового обігу (RTT): Очікуючи відправлення в локальній пам\x27яті десятками або сотнями мілісекунд, пакети штучно завищували показник RTT. Це дезорієнтувало алгоритми контролю перевантаження і знижувало точність їх реакції.
- Блокування відновлення після втрат: Якщо у віддаленій мережі виникала втрата пакета, черга застарілих даних у буфері драйвера все одно мала передатися до кінця, перш ніж туди міг потрапити пакет повторної передачі.
- Деградація інтерактивного трафіку: Сесії терміналів SSH, запити DNS та голосові пакети VoIP опинялися заблокованими позаду величезних сплесків передачі файлів.
Алгоритми активного керування чергами (AQM), як-от CoDel та FQ-CoDel, розроблялися для боротьби з переповненням буферів у маршрутизаторах, але вони не можуть працювати оптимально, коли локальний транспортний стек вивантажує трафік гігантськими монолітними блоками. Потрібен був надійний обмежувач прямо на межі транспортного рівня.
Принцип динамічного регулювання черги сокета в TSQ
Архітектура TCP Small Queues запроваджує механізм точного зворотного зв\x27язку між апаратним завершенням передачі кадрів і формуванням нових пакетів сокетом. Замість сприйняття черги мережевої плати як бездонного накопичувача, TSQ контролює точний обсяг байтів, які вже передані драйверу, але ще не вийшли в лінію зв\x27язку.
Контроль пам\x27яті за допомогою sk_wmem_alloc
Кожен буфер sk_buff, сформований сокетом, збільшує лічильник використання пам\x27яті запису (sk->sk_wmem_alloc). Цей показник враховує корисне навантаження, службові заголовки та фрагменти сторінок пам\x27яті. Коли мережева карта або віртуальний інтерфейс TUN закінчує відправлення кадру, апаратне переривання вивільняє пам\x27ять (kfree_skb), зменшуючи значення sk_wmem_alloc.
Перед тим як сегментувати наступний блок даних, підсистема TCP оцінює, чи не перевищує поточний обсяг у польоті допустиму межу TSQ:
static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb, unsigned int factor)
{
unsigned int limit = max(2 * skb->truesize, sk->sk_pacing_shift);
limit = min_t(unsigned int, limit, sysctl_tcp_limit_output_bytes);
if (atomic_read(&sk->sk_wmem_alloc) > limit) {
set_bit(TSQ_THROTTLED, &tcp_sk(sk)->tsq_flags);
return true; /* Призупинити подальше відправлення */
}
return false;
}
Якщо показник sk_wmem_alloc перевищує встановлений ліміт, ядро виставляє прапорець TSQ_THROTTLED на відповідному сокеті і припиняє передачу нових пакетів донизу. Це унеможливлює ситуацію, коли одне з\x27єднання монополізує чергу обладнання.
Пробудження сокета після завершення апаратної передачі
Коли драйвер пристрою завершує відправлення кадру й звільняє пам\x27ять за допомогою skb_destroy(), ядро перевіряє наявність прапорця TSQ_THROTTLED. Якщо прапорець активний, планувальник поміщає сокет у спеціальну чергу задач процесора (tsq_tasklet), яка негайно викликає функцію tcp_tsq_handler().
Ця функція знімає статус обмеження й викликає tcp_write_xmit(), надсилаючи наступну дозовану партію даних. Оскільки цей цикл триває лічені мікросекунди за сигналами апаратних переривань, з\x27єднання підтримує граничну пропускну здатність каналу при мінімальній глибині черги.
Взаємодія між TSQ, пейсингом пакетів та алгоритмом Sch_FQ
Архітектура TSQ розкриває свій максимальний потенціал у поєднанні з пейсингом (Packet Pacing) та дисципліною чесних черг (sch_fq). Пейсинг рівномірно розподіляє вихідні пакети в часі відповідно до розрахункового RTT замість викидання цілого вікна сегментів у момент отримання підтвердження ACK.
За замовчуванням ядро Linux автоматично масштабує ліміт TSQ на основі темпу пейсингу сокета:
$$\text{TSQ Limit} = \max\left(2 \times \text{MSS}, \text{Pacing Rate} \times 1\text{ ms}\right)$$
Для каналу зі швидкістю 1 Гбіт/с один мілісекундний інтервал відповідає приблизно 125 КБ даних у черзі. Для каналу зі швидкістю 100 Мбіт/с цей ліміт автоматично скорочується до 12.5 КБ. Таким чином, глибина черги динамічно підлаштовується під реальну ємність лінії передачі.
┌─────────────────────────┐
│ Транспортний сокет │
└────────────┬────────────┘
│ Перевірка sk_wmem_alloc
┌─────────────────────┴─────────────────────┐
│ │
sk_wmem_alloc <= Limit sk_wmem_alloc > Limit
│ │
▼ ▼
Передати до sch_fq / Pacing Встановити TSQ_THROTTLED
│ (Пауза сокета)
▼ │
[ Мінімальна черга TX ] │
│ │
▼ │
Апаратне надсилання / TUN ──────── Завершення ──────────────┘
kfree_skb()
У комбінації з sch_fq кожен активний сокет отримує власну ізольовану віртуальну чергу. Механізм TSQ гарантує, що в кожній черзі знаходиться рівно стільки байтів, скільки потрібно для повного завантаження лінії, запобігаючи стрибкам джитера (Jitter).
Вплив на віртуальні інтерфейси TUN та зашифровані мережі VPN
Локальний буферблот становить особливу загрозу у віртуалізованих архітектурах VPN. У сучасних тунелях вихідні зашифровані пакети проходять крізь віртуальний мережевий адаптер (tun0 або wg0), перш ніж потрапити до фізичного інтерфейсу Ethernet або Wi-Fi.
Проблема подвійного накопичення буферів
Без активного регулювання TSQ віртуальні тунелі стикаються з ефектом каскадного буферблоту:
- Буферблот віртуального адаптера: Внутрішній потік TCP переповнює чергу інтерфейсу
tunпакетами, що очікують на шифрування та інкапсуляцію. - Буферблот фізичного адаптера: Зовнішній сокет UDP перевантажує буфери фізичної мережевої плати зашифрованими датаграмами.
Таке багатошарове накопичення може призводити до зростання затримки з 20 мс до понад 350 мс під час активного трафіку. Втрата пакета в зовнішньому тунелі спричиняє повторну передачу внутрішнього стека, яка застрягає позаду масивних застарілих черг.
Реалізація низької затримки в архітектурі RiceGuard
У сучасній екосистемі RiceGuard процеси інкапсуляції оптимізовані для взаємодії зі стеком обліку пам\x27яті ядра Linux. Завдяки точному узгодженню віртуального MTU з межами апаратної сегментації та дотриманню правил TSQ, дескриптори віртуального тунелю не утримують зайвих невідправлених даних.
У поєднанні з маршрутизацією Core L3 VPN та архітектурою передачі без копіювання пам\x27яті (zero-copy), TSQ дозволяє пакетам голосового та ігрового трафіку випереджати об\x27ємні потоки передачі файлів за лічені мікросекунди. Замість очікування вивільнення 4-мегабайтної черги драйвера інтерактивні дані одразу проходять крізь практично порожні черги передачі.
Практичний моніторинг та налаштування параметрів Sysctl
Адміністратори Linux можуть перевіряти та коригувати параметри TSQ за допомогою стандартних системних утиліт.
Перевірка глобального ліміту TSQ
Глобальний поріг обсягу байтів, дозволений сокету для накопичення в чергах обладнання, визначається параметром sysctl:
# Перегляд поточного ліміту TSQ (стандартне значення зазвичай 262144 байти / 256 КБ)
sysctl net.ipv4.tcp_limit_output_bytes
Для оптимізації серверних шлюзів VPN із великою кількістю одночасних сесій цей поріг можна зменшити, що запобігає надмірному виділенню пам\x27яті та знижує локальну затримку:
# Встановлення межі 128 КБ для шлюзів із високими вимогами до затримки
sudo sysctl -w "net.ipv4.tcp_limit_output_bytes = 131072"
Відстеження подій спрацьовування TSQ
Утиліта діагностики сокетів ss надає детальну інформацію про поточний стан черг кожного з\x27єднання TCP:
# Діагностика активних підключень на порту 443
ss -tin '( dport = :443 or sport = :443 )'
Серед виведених телеметричних параметрів ключове значення мають такі поля:
wmem_alloc: Загальний обсяг пам\x27яті запису, виділений під пакети, що очікують відправлення.tsq: Прапорець, який вказує, що для цього сокета наразі застосовано обмеження TSQ.pacing_rate: Розрахована швидкість передачі, визначена алгоритмом керування перевантаженням (наприклад, BBR).bytes_acked: Загальна кількість успішно підтверджених байтів даних.
Якщо параметр wmem_alloc стабільно утримується на рівні нижче 150 КБ під час насичення пропускної здатності каналу, це свідчить про ефективне придушення локального буферблоту.
Підсумок: Фундамент сучасних мереж із низькою затримкою
Архітектура TCP Small Queues стала визначальним кроком у розвитку мережевого стека сучасних операційних систем. Завдяки обмеженню розміру буферів безпосередньо на рівні сокета з урахуванням темпу передачі, TSQ назавжди ліквідувала проблему виснажливого локального буферблоту в Linux.
Для високошвидкісних зашифрованих тунелів VPN ця технологія перетворює віртуальні адаптери з вузьких місць на швидкісні й передбачувані канали зв\x27язку. Разом із чесним плануванням черг та оптимізованими протоколами TSQ забезпечує ідеальний баланс між високою швидкістю завантаження файлів і мінімальною затримкою чутливого інтерактивного трафіку.



