Що таке алгоритм Нейгла і як він впливає на онлайн-ігри?

Останнє оновлення: 27/02/2026

  • Алгоритм Нейгла зменшує кількість tinygram, обмежуючи їх невеликим сегментом без підтвердження на кожне з'єднання, що підвищує ефективність у повільних мережах, але додає затримки.
  • Його взаємодія із затриманими підтвердженнями (ACK) може вводити паузи тривалістю до 500 мс у шаблонах запис-запис-читання та протоколах запит-відповідь.
  • TCP_NODELAY та TCP_QUICKACK дозволяють вимкнути Nagle та/або Delayed ACK для визначення пріоритету затримки в інтерактивних програмах та сучасних розподілених системах.
  • Рішення про використання Nagle чи ні має ґрунтуватися на фактичній схемі трафіку: величезна пропускна здатність проти критичної односторонньої затримки.
алгоритм Нагла

Під час роботи з мережами, сокетами або просто у разі боротьби із затримкою TCP-додатків, зіткнення з сумнозвісною проблемою – це лише питання часу. Алгоритм Нейгла (Алгоритм НейглаЦе один із тих механізмів у стеку TCP/IP, який ми майже ніколи не налаштовуємо вручну на початку, але він може мати вирішальне значення між плавною роботою програми та тією, яка працює «заїкаючись» із загадковими затримками в сотні мілісекунд.

У цій статті ми спокійно розглянемо, що являє собою алгоритм Нейгла, яку проблему він прагнув вирішити у 80-х роках, і як він поєднується (іноді фатально) з механізмом затримки ACK. коли доречно його вимикати Ми розглянемо TCP_NODELAY та опції, доступні в основних операційних системах для налаштування його поведінки. Все пояснено просто.

Що таке алгоритм Нейгла і яку проблему він намагається вирішити?

Алгоритм Нейгла виник із дуже конкретної потреби: уникнути лавини крихітних пакетів (мініграмів) що перенасичувало повільні мережі на зорі TCP. Уявіть собі інтерактивні термінальні програми, де кожне натискання клавіші надсилало один байт: для кожного символу передавався 1 корисний байт плюс 20 байтів заголовка TCP та 20 байтів заголовка IP. Тобто загалом 41 байт, з яких лише 1 був фактично даними: накладні витрати в 4000%, абсолютний абсурд, якщо повторювати це тисячі разів.

Джон Нейгл запропонував «просте та елегантне» рішення: доки є дані, надіслані без підтвердження (без ACK) У TCP-з'єднанні відправник повинен стримуватися та не надсилати нові маленькі сегменти. Таким чином, замість того, щоб надсилати крихітні пакети один за одним, система чекає на отримання підтвердження (ACK) або на накопичення додаткових даних, щоб можна було сформувати більші та ефективніші сегменти.

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

Така логіка робить алгоритм певною мірою самоадаптивним: чим повільніша мережа або чим більша затримка, тим довше потрібно для повернення підтверджень (ACK) і тим більше даних групується в кожному сегменті. На WAN-з'єднаннях з високою затримкою та відносно обмеженою пропускною здатністю це було справжнім досягненням для покращення продуктивності. загальна ефективність руху транспорту.

Алгоритм Нейгла

Формальне визначення та внутрішнє функціонування

Оригінальна специфікація алгоритму Нейгла, що міститься в RFC 896 про контроль перевантаження в мережах IP/TCP, підсумовує його поведінку наступним чином: він повинен заборонити надсилання нових TCP-сегментів Коли дані надходять від програми, вона перевіряє, чи є раніше передані дані, які ще не були розпізнані. Виходячи з цього визначення, багато реалізацій виражають його у псевдокоді.

На практиці логіку для кожного TCP-з'єднання можна сформулювати так: якщо надходять нові дані і вікно доставки Якщо дозволена кількість непідтверджених даних більша або дорівнює MSS, і в буфері є щонайменше MSS байтів, негайно надсилається повнорозмірний сегмент MSS. Якщо ця умова не виконується, але «в конвеєрі» все ще є непідтверджені дані, ці нові дані ставляться в чергу та очікується підтвердження (ACK). Коли непідтверджених даних немає, будь-які нові дані, отримані від програми, надсилаються негайно.

Зрештою, важливим є зв'язок між MSS (Максимальний розмір сегмента)Розмір вікна та обсяг даних, які програма поступово виводить, є ключовими факторами. Якщо потік програми дуже гранулярний (багато невеликих записів), Nagle діє як «лійка» та групує дані; якщо дані більш об’ємні, вплив розбавляється, а алгоритм є менш нав’язливим.

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

Ексклюзивний вміст - натисніть тут  Як завантажити титульні сторінки для Word

Затримані підтвердження: затримані підтвердження для зменшення накладних витрат

Паралельно з Нейглом, і приблизно в той самий час, у TCP було запроваджено ще одну оптимізацію, яка так само відома й сьогодні: Затримане підтвердженняІдея була дуже розумною для мереж того часу: якщо ви щойно отримали сегмент і збираєтеся відправити дані назад, чому б не почекати трохи та не використати цей вихідний пакет для "підкріплення" підтвердженням (ACK) в тому ж заголовку?

Цей механізм базується на таймері: після отримання даних приймач зберігає підтвердження (ACK) і чекає короткий інтервал (зазвичай від 200 до 500 мс), щоб побачити, чи з'явиться воно протягом цього часу. вихідний трафік до якого можна додати підтвердження. Якщо нічого не надходить, коли час таймера закінчується, підтвердження надсилається окремо.

Результатом є зменшення загальної кількості підтверджень (ACK), що циркулюють у мережі, що економить заголовки TCP/IP та зменшує навантаження на маршрутизатори та кінцеві точки. У багатьох випадках, особливо з інтерактивними протоколами, що використовують відлуння символів (наприклад, деякі конфігурації Telnet), одержувач може групувати кілька підтверджень (ACK) в одне ACK, не впливаючи на сприйняту затримку.

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

 

Вибухова комбінація: Нейгл + Затриманий ACK

Основна практична проблема Нейгла виникає не сама по собі, а радше в поєднанні з... затримані підтвердженняОбидві функціональності були розроблені незалежно на початку 80-х років, і, за словами самого Нейгла, їхнє поєднання «жахливе». Між ними немає чіткої координації, тому вони можуть потрапити у своєрідний цикл взаємного очікування.

Уявіть собі програму, яка виконує два послідовних запису через TCP-з'єднання, а потім читання, очікуючи даних, згенерованих другим записом. Якщо ввімкнено Nagle, після першого невеликого сегмента стек TCP не надсилатиме другий невеликий пакет, доки не отримає підтвердження (ACK) для першого. Але якщо одержувач використовує відкладене підтвердження (Delayed ACK), це підтвердження не буде надіслано негайно; натомість воно чекатиме, поки його можна буде приєднати до пакета відповіді або поки не закінчиться таймер 200-500 мс.

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

Ця закономірність особливо шкідлива в протоколах неконвеєризований запит-відповідь, наприклад, HTTP через постійні з'єднання, коли запити або відповіді розділені на кілька сегментів, а останній пакет є частковим. З оригінальним алгоритмом, якщо запис згенерував 2n сегменти, де перші 2nПерший сегмент був повного розміру, а останній — маленького; TCP утримував маленький сегмент, очікуючи на підтвердження (ACK). Якщо одержувач також затримував підтвердження (ACK), маленький сегмент відставав би до півсекунди.

затримка в іграх

Коли має сенс відключити Nagle: TCP_NODELAY

Сучасні TCP-стеки часто надають опцію сокета для явного вимкнення Nagle: добре відомий Опція TCP_NODELAYВін доступний з версії 4.2BSD (1983) і був успадкований багатьма нащадками, включаючи більшість систем Unix, macOS та Windows. Наприклад, у AIX та Windows Nagle увімкнено за замовчуванням і може бути вимкнено для кожного сокета за допомогою цього прапорця.

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

У цих середовищах затримка в сотні мілісекунд, яку може створити комбінація Nagle + Delayed ACK, є неприйнятною: користувач чітко відчуває, що інтерфейс не відповідає вчасно. Тому багато програм з низькою затримкою вмикають TCP_NODELAY для всіх своїх з'єднань, жертвуючи деякою ефективністю заголовків в обмін на набагато швидшу взаємодію.

Ексклюзивний вміст - натисніть тут  Як зробити скріншот на Mac?

Також часто фреймворки та бібліотеки для "балакучих" протоколів, таких як певні тунелі SSL/TLS, рішення типу Citrix або системи, що виконують багато коротких обмінів керуванням, обирають вимкнути Nagle за замовчуваннямтому що на практиці це коштує їм більше на затримці, ніж вони економлять на головних станціях.

Однак, для масивного трафіку, такого як HTTP, SOAP, завантаження XMLRPC або передача великих файлів, де пропускна здатність є домінуючою, а вартість кожного заголовка незначна порівняно з обсягом даних, підтримка Nagle активним зазвичай не є проблематичною, і в багатьох випадках немає помітної різниці після його вимкнення.

Чи має сенс Нейгл у сучасних системах?

Якщо ми розглянемо сучасні мережі з центрами обробки даних, де час передачі даних туди й назад (RTT) вимірюється в сотні мікросекунд або кілька мілісекунд між сусідніми регіонами, початкове обґрунтування Нейгла втрачає свою силу. Блокування передачі сегмента до наступного підтвердження (ACK) більше не передбачає секунд очікування, але може бути зайвою перешкодою, коли кожна мікросекунда має значення.

Крім того, в наш час серйозні програми рідко надсилають необроблені 1-байтові пакети. Більшість розподілених систем, баз даних та бекенд-сервісів створюють більші повідомлення, використовують TLS (що додає власних накладних витрат) та серіалізують дані за допомогою JSON, Protobuf та похідних. Основна проблема з tinygrams була "вирівняна" та значною мірою вирішується з... прикладний рівень, який зазвичай логічно групує інформацію перед тим, як вивантажити її в сокет.

Ось чому багато інженерів, які проектують сервіси з низькою затримкою в сучасних центрах обробки даних, починають з дуже прагматичного правила: для їхнього внутрішнього контрольного трафіку безпечним варіантом є завжди вмикати TCP_NODELAY, і будь-які проблеми з пропускною здатністю будуть вирішуватися іншим способом. Іншими словами, краще ризикнути, використовуючи кілька додаткових заголовків, ніж запроваджувати блокування multi-RTT у критичних точках бізнес-логіки.

Це не означає, що Нейгл перестав бути корисним, особливо в контексті вузькі або дуже шумні канали (наприклад, SLIP, певні мобільні або супутникові канали), де кожен пакет є дорогим. Але це підкріплює ідею про те, що його використання має бути усвідомленим: у багатьох сучасних корпоративних розгортаннях налаштування за замовчуванням, яке його ввімкнуло, не найкраще підходить для програм, що працюють поверх нього.

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

Вимкнути затримане підтвердження: TCP_QUICKACK та інші механізми

Інший спосіб обійти проблеми комбінації Nagle + Delayed ACK — це звернути увагу на інший бік: замість того, щоб вимикати Nagle, вимкніть або пом'якшіть поведінку затриманих ACK. Тут ситуація складніша, оскільки інтерфейси значно відрізняються між операційними системами.

У Linux є прапорець TCP_QUICKACK Починаючи з ядра 2.4.4 (2001), це дозволяє швидше запитувати у стека розпізнавання вхідних сегментів. Подібні або споріднені механізми також існують у Windows, такі як операція SIO_TCP_SET_ACK_FREQUENCY, а також параметри журналювання, такі як TcpAckFrequency, які, якщо їх встановити на 1, примусово надсилають підтвердження (ACK).

У FreeBSD поведінка відкладених ACK-підтверджень за замовчуванням контролюється параметром sysctl. net.inet.tcp.delayed_ackякий можна налаштувати, щоб зробити підтвердження більш агресивними або послабшими за потреби. Однак у Linux немає такого простого глобального еквівалентного перемикача: обробка затриманих ACK глибше вбудована у внутрішню логіку TCP.

Хоча ці опції існують, багато розробників розподілених систем використовують їх обережно. З одного боку, Вони не є портативними Міжплатформна сумісність ускладнює написання підтримуваного універсального коду; крім того, його семантика іноді неінтуїтивно зрозуміла та залежить від версії ядра. Більше того, навіть зі швидкими підтвердженнями (ACK) ядро ​​може тимчасово зберігати дані, які програма воліла б надіслати негайно, тому корінна причина проблеми не усувається.

З усіх цих причин у багатьох випадках кращою тактикою є більш пряма: якщо пріоритетом є те, щоб кожен виклик write() насправді означав «надіслати це зараз», то тенденція полягає в активації TCP_NODELAY та прийнятті невеликих витрат у заголовках, замість того, щоб намагатися приборкати поведінку затриманого ACK за допомогою системно-специфічних прапорців.

Ексклюзивний вміст - натисніть тут  Як переглядати веб-сторінки в режимі анонімного перегляду в Chrome

Як вирішити, чи вмикати чи вимикати TCP_NODELAY

Велике практичне питання полягає в наступному: коли доцільно вмикати Nagle, а коли краще вимикати його за допомогою TCP_NODELAY? Універсального правила немає, але є досить чіткі рекомендації, засновані на типі трафіку та спостережуваній поведінці.

Якщо ваш сервіс переважно обслуговує об'ємні перекази Для неінтерактивних завдань (завантаження файлів, великі HTTP-відповіді, добре буферизовані потокові потоки) пріоритетом зазвичай є пропускна здатність та загальна ефективність. У цих випадках залишати Nagle увімкненим є розумним і рідко призводить до помітних проблем із затримкою.

І навпаки, якщо ви маєте справу з високоінтерактивними програмами, які надсилають багато невеликих повідомлень — онлайн-ігри, віддалені робочі столи, Citrix, певні SSL-тунелі або протоколи, що вимагають численних коротких рукостискань — Nagle, як правило, стає перешкодою. Увімкнення TCP_NODELAY зазвичай призводить до явні покращення швидкості реагування для користувача.

Більш аналітичний спосіб розгляду цього питання — це інструментальний аналіз мережі та спостереження за статистикою, такою як кількість tinygram (пакетів з дуже малим корисним навантаженням) та кількість затримок, пов'язаних з Nagle. Інструменти поглибленого аналізу трафіку можуть допомогти вам побачити, який відсоток ваших пакетів є крихітними та скільки часу вони «застрягли» через ці механізми.

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

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

Альтернативи та рішення, коли TCP не підходить

У деяких екстремальних сценаріях навіть вимкнення Nagle та налаштування відкладеного підтвердження (Delayed ACK) недостатньо для досягнення бажаної затримки. Якщо ваша програма постійно надсилає крихітні кадри, і будь-яка додаткова затримка є неприйнятною, TCP може бути не найкращим транспортним протоколом для вас.

У цих випадках багато розробників обирають протоколи без встановлення з'єднання, такі як Уніфікований діловий процес (UDP)У цьому середовищі немає контролю перевантаження або гарантій доставки, але є мінімальна затримка та повна відсутність механізмів, таких як Nagle або затримані підтвердження (ACK). Однак усе, що TCP робить для вас — повторні передачі, упорядкування, контроль втрат тощо — має бути реалізовано на рівні програми.

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

У великих корпоративних середовищах вони також використовують налаштування балансувальників навантаження та проксі-серверівЦе дозволяє динамічно вмикати або вимикати TCP_NODELAY залежно від типу виявленого трафіку або вибірково зменшувати таймери затримки ACK. Такий підхід дозволяє адаптувати поведінку до дуже неоднорідних сумішей трафіку без необхідності внесення змін до всіх кінцевих програм.

У будь-якому разі, перш ніж витрачати гроші на додаткове обладнання або нові з'єднання, зазвичай дуже варто перевірити, чи ваші параметри TCP (Nagle, Delayed ACK, розмір вікна, буфери тощо) дійсно відповідають фактичним моделям використання вашої мережі. Нерідко добре виконані налаштування на цих рівнях дозволяють досягти значних покращень без зміни жодного кабелю.

З огляду на все вищесказане, глибоке розуміння того, як працює алгоритм Нейгла та як він взаємодіє (або добре працює) із затриманим ACK, TCP_NODELAY та TCP_QUICKACK, є майже обов'язковим, якщо вас турбують затримка та продуктивність у ваших TCP-застосунках: зрештою, рішення про те, чи надавати пріоритет ефективності чи негайності в кожному випадку, є тим, що визначає різницю між мережею, яка «працює сама по собі», та тією, яка, здається, завжди працює з увімкненим ручним гальмом.