Якщо ваш хост на Debian 13 раптом починає «відкидати інтернет», при тому що CPU в нормі, а диски без діла, перевірте журнал ядра. Коли ви бачите nf_conntrack: table full, dropping packet, це не абстрактне попередження. Це жорстка межа ємності в підсистемі відстеження з’єднань ядра, і нові потоки тепер платять за це.
Це один із таких режимів відмови, що змушує розумних людей казати сумнівні речі на кшталт «але TCP має повторити». Має. Поки ваш балансувальник навантаження божеволіє, користувачі оновлюють сторінку, проби стають червоними — всі дізнаються, що стек мережі має обмежені ресурси.
Що таке conntrack (і чому це важливо в Debian 13)
nf_conntrack — це система відстеження з’єднань у Linux. Вона зберігає стан мережевих потоків, щоб Netfilter міг виконувати stateful-фаєрвол і NAT. Цей «стан» зберігається в таблиці ядра: записи для потоків типу TCP, UDP та деяких ICMP-розмов. Це не опціонально, якщо ви робите звичні речі на кшталт:
- Stateful-правила фаєрволу (
ct state established,related/-m conntrack --ctstate) - NAT / маскарадування (типово для контейнерів, вузлів Kubernetes, домашніх роутерів та «тимчасових» корпоративних хаків, що стають постійними)
- Балансувальники навантаження або зворотні проксі на хості, який також робить NAT для чогось іншого
- Будь-що, що покладається на відстеження відповідей (FTP-хелпери, деяка поведінка SIP та інші радощі з минулого)
Коли таблиця заповнюється, ядро не може виділити новий запис для нового потоку. Тому воно відкидає пакети, які створювали б новий стан. Існуючі потоки можуть рухатися повільно далі, але видима користувачам поведінка — «випадкові» відмови: деякі з’єднання працюють, деякі зависають, деякі повторно передаються, деякі таймаутяться.
Цікаві факти й контекст (бо в цієї проблеми є історія)
- Conntrack з’явився в еру Netfilter на початку 2000-х, щоб дозволити stateful-фаєрвол та NAT у Linux без зовнішніх пристроїв.
- Історично багато інцидентів «моєму фаєрволу нічого не бракує» були насправді виснаженням conntrack — правила фільтрації були вірні, але таблиця стану була замала.
- У сучасних стек-платформах із контейнерами conntrack став спільним ресурсом: один вузол Kubernetes може відстежувати трафік для багатьох подів і сервісів, тому сплески вдаряють сильніше.
- За замовчуванням розміри conntrack свідомо консервативні, щоб уникнути великих витрат пам’яті на маленьких машинах. Добре для ноутбуків. Погано для навантажених шлюзів.
- NAT агресивно споживає записи conntrack, бо кожен переклад потрібно відстежувати; додайте короткоживучі з’єднання — і турбулентність злетить.
- UDP «з’єднання» умовні, але все одно відстежуються, а їхні таймаути можуть тихо утримувати записи довго після того, як додаток вже припинив піклуватися.
nf_conntrack_buckets(бакети хеш-таблиці) впливають на продуктивність пошуку; велика таблиця з замалою кількістю бакетів схожа на телефонний довідник з однією вкладкою літери.- Навантажувальне тестування часто пропускає тиск на conntrack, бо фокусується на пропускній здатності додатка, а не на частоті потоків і таймаутах.
- Деякі відмови, які списували на «DDoS», були насправді нормальним трафіком плюс зміна таймаутів, що утримувала записи довше.
Операційне правило: проблеми conntrack рідко з’являються під час спокійного навантаження. Вони з’являються під час деплоїв, переносів, флеш-кроудів або коли хтось змінив таймаути без повідомлення. Тому ставтеся до conntrack як до ємнісного планування, а не як до аварійного важеля.
Чому з’єднання відмовляють, коли таблиця заповнена
Коли приходить пакет, для якого потрібен стан conntrack (новий TCP SYN, нова «сесія» UDP, відповідь, що потребує NAT-мапінгу), ядро намагається виділити запис conntrack. Якщо не може — ви отримуєте запис у журналі і відкинутий пакет. Нові з’єднання відмовляють такими способами:
- TCP SYN повторюються, доки клієнт не здасться (виглядає як втрата пакетів)
- DNS таймаути (UDP-запити відкидаються, відбуваються повтори, затримки зростають)
- Вихідні HTTP виклики зависають (особливо з вузлів, що роблять NAT)
- Перервні помилки сервісного виявлення в Kubernetes
Існуючі встановлені TCP-потоки часто продовжують роботу, бо їхні записи conntrack вже існують. Це створює класичний симптом «половина світу працює»: ваш SSH-сеанс залишається живим, але нові підключення не проходять. У чаті інциденту з’являється купа забобонів.
Жарт №1: Виснаження conntrack — це єдиний випадок, коли «stateful» мережі стає «stateless» навмисно, і нікому не до вподоби така чистота.
Справжнє вузьке місце: записи, а не пропускна здатність
Ємність conntrack вимірюється кількістю відстежуваних потоків, а не бітами за секунду. Хост може мати багато пропускної здатності і все одно впасти через те, що закінчилися записи через:
- Багато короткоживучих з’єднань (мікросервіси з балакучими HTTP-клієнтами)
- Великий розгалуження (one-to-many calls — один сервіс викликає десятки інших на запит)
- UDP-навантаження (DNS, QUIC, телеметрія) з надто довгими таймаутами
- NAT-шлюзи для багатьох клієнтів (записи накопичуються для кожного клієнта)
- Атаки, сканування або бот-шум (навіть за наявності обмежень)
Цитата, бо в операцій є свої філософи
перефразована ідея
— «Надійність походить із проєктування для відмов, а не з удавання, що їх не буде.» Приписують: John Allspaw (reliability/operations).
Швидкий посібник діагностики
Цей порядок допомагає швидко знайти вузьке місце, не заглиблюючись у 40 лічильників і кролячу нору «може то DNS». Порядок такий:
-
Спочатку: підтвердіть, що це саме виснаження conntrack, а не просто втрата пакетів.
- Перевірте журнали ядра на «table full».
- Перевірте поточне використання та максимум.
-
По-друге: визначте, що створює записи.
- Порахуйте записи conntrack за протоколом/станом.
- Шукайте великі об’єми UDP або купи
SYN_SENT/SYN_RECV. - Перевірте, чи хост робить NAT (контейнери, Kubernetes, VPN, класичне masquerade).
-
По-третє: вирішіть, чи збільшити max, скоротити таймаути або вимкнути відстеження.
- Якщо ви регулярно біля максимуму: збільште ємність і бакети, потім перевірте вплив на пам’ять.
- Якщо це лише сплески: зменшіть таймаути для порушника і/або виправте fan-out чи шторми повторів.
- Якщо ви відстежуєте трафік, який не потрібен: вимкніть відстеження для цих потоків (обережно).
Все інше — CPU-профілювання, красиві дашборди, звинувачення фаєрволу — для після того, як ви підтвердили тиск на таблицю. Conntrack або повний, або ні.
Практичні дії: команди, виводи, рішення
Ось реальні дії, які можна виконати на Debian 13. Кожна містить пояснення, що означає вивід і яке рішення ухвалити. Виконуйте з root або з відповідними правами.
Завдання 1: Підтвердити, що ядро відкидає через conntrack
cr0x@server:~$ sudo journalctl -k -g "nf_conntrack" -n 20 --no-pager
Dec 29 10:41:12 server kernel: nf_conntrack: table full, dropping packet
Dec 29 10:41:12 server kernel: nf_conntrack: table full, dropping packet
Dec 29 10:41:13 server kernel: nf_conntrack: table full, dropping packet
Значення: Це «димова гарпуна». Ядро відмовляє у нових виділеннях conntrack і відкидає пакети.
Рішення: Перестаньте гадати. Перейдіть до вимірювань використання і визначення, що заповнює таблицю.
Завдання 2: Подивитися поточне використання проти налаштованого максимуму
cr0x@server:~$ sudo sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_count = 262144
net.netfilter.nf_conntrack_max = 262144
Значення: Ви на межі. Count дорівнює max, і нові потоки будуть відкинуті.
Рішення: Потрібне полегшення: або підвищити max (після перевірки пам’яті), або зменшити таймаути, або зменшити кількість відстежуваних потоків.
Завдання 3: Перевірити споживання пам’яті conntrack (slab)
cr0x@server:~$ grep -E 'nf_conntrack|conntrack' /proc/slabinfo | head -n 3
nf_conntrack 262144 262144 320 256 8 : tunables 0 0 0 : slabdata 1024 1024 0
nf_conntrack_expect 0 0 96 42 1 : tunables 0 0 0 : slabdata 0 0 0
Значення: Slab nf_conntrack показує, скільки об’єктів виділено і їхній розмір. Тут записи повністю виділені.
Рішення: Оцініть вплив на пам’ять перед підвищенням max. Якщо пам’ять підтискає, безпечнішим буде зменшення таймаутів або зниження кількості потоків.
Завдання 4: Якщо встановлено conntrack-tools, отримати коротку зведення
cr0x@server:~$ sudo conntrack -S
cpu=0 found=1483921 invalid=121 insert=927314 insert_failed=8421 drop=8421 early_drop=0 error=0 search_restart=0
Значення: Зростання insert_failed та drop вказує на відмови виділення — зазвичай таблиця повна, іноді тиск на хеш.
Рішення: Якщо insert_failed росте, ви активно відкидаєте нові потоки. Мітигуйте зараз; налаштовуйте після.
Завдання 5: Порахувати записи за протоколом (швидка «теплова мапа»)
cr0x@server:~$ sudo conntrack -L | awk '{print $1}' | sort | uniq -c | sort -nr | head
210944 tcp
50877 udp
323 icmp
Значення: Тут домінує TCP. Якщо домінує UDP, доведеться глибше дивитись на DNS/QUIC/телеметрію і таймаути UDP.
Рішення: Оберіть наступний напрямок розслідування: розподіл станів TCP або турбулентність UDP-таймаутів.
Завдання 6: Для TCP знайти, які стани роздуваються
cr0x@server:~$ sudo conntrack -L -p tcp | awk '{for (i=1;i<=NF;i++) if ($i ~ /^state=/) {split($i,a,"="); print a[2]}}' | sort | uniq -c | sort -nr | head
80421 ESTABLISHED
61211 TIME_WAIT
45433 SYN_SENT
12912 CLOSE_WAIT
Значення: Багато SYN_SENT може означати зовнішні шторми або відсутність відповіді від апстріму. Багато TIME_WAIT може відображати короткоживучі з’єднання і турбулентність.
Рішення: Якщо SYN_SENT високо — шукайте повтори і доступність апстріму; якщо TIME_WAIT високо — працюйте над повторним використанням підключень у додатку.
Завдання 7: Виявити топ-джерела за призначенням (виявити безконтрольну залежність)
cr0x@server:~$ sudo conntrack -L -p tcp | awk '{for(i=1;i<=NF;i++){if($i ~ /^dst=/){split($i,a,"="); print a[2]}}}' | sort | uniq -c | sort -nr | head
64221 10.10.8.21
33110 10.10.8.22
12044 192.0.2.50
Значення: Один-два напрямки споживають велику частину таблиці. Зазвичай це залежність у відмові, шторм повторів або точка агрегації NAT.
Рішення: Зберіть логи/метрики клієнтів, що говорять із цими IP. Розгляньте обмеження швидкості або circuit breaking перед правкою sysctl.
Завдання 8: Перевірити, чи є NAT (nftables)
cr0x@server:~$ sudo nft list ruleset | sed -n '/table ip nat/,/}/p'
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "eth0" masquerade
}
}
Значення: Хост робить masquerade NAT. Кожен трансльований потік потребує відстеження, і клієнти з вибуховими сплесками можуть швидко заповнити таблицю.
Рішення: Розглядайте цей хост як шлюз. Розмірюйте conntrack під агреговану поведінку клієнтів, а не під один сервіс.
Завдання 9: Перевірити кількість бакетів і максимум (хеш-розмір)
cr0x@server:~$ sudo sysctl net.netfilter.nf_conntrack_buckets net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_buckets = 65536
net.netfilter.nf_conntrack_max = 262144
Значення: Загальна порада: nf_conntrack_max ≈ 4× бакетів (не закон, але гідна відправна точка). Тут співвідношення рівно 4.
Рішення: Якщо ви суттєво підвищите max — перегляньте бакети також. Інакше під час навантаження платитимете CPU за довгі хеш-ланцюги.
Завдання 10: Перевірити поточні таймаути (прихований важіль ємності)
cr0x@server:~$ sudo sysctl net.netfilter.nf_conntrack_tcp_timeout_established net.netfilter.nf_conntrack_udp_timeout net.netfilter.nf_conntrack_udp_timeout_stream
net.netfilter.nf_conntrack_tcp_timeout_established = 432000
net.netfilter.nf_conntrack_udp_timeout = 30
net.netfilter.nf_conntrack_udp_timeout_stream = 180
Значення: Established TCP тут утримується 5 діб. Це не «помилка», але на навантажених NAT-боксах може бути катастрофою, якщо клієнти зникають некоректно.
Рішення: Якщо бачите багато встановлених записів, що є застарілими (клієнт пішов), розгляньте зменшення таймаута — обережно, з урахуванням довгоживучих з’єднань.
Завдання 11: Проінспектувати поведінку по просторах імен (контейнери/Kubernetes)
cr0x@server:~$ sudo lsns -t net | head
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531993 net 245 1 root unassigned /lib/systemd/systemd
4026532458 net 12 3112 root unassigned /usr/bin/containerd
Значення: Існує кілька мережевих просторів імен, але conntrack залишається в основному глобальним ресурсом ядра (з деяким обліком per-netns залежно від налаштувань). Контейнери можуть несподівано спричиняти турбулентність потоків.
Рішення: Якщо це вузол, врахуйте трафік подів/сервісів при розмірюванні. Не розраховуйте лише на «додаток на хості».
Завдання 12: Виміряти турбулентність з’єднань на рівні сокетів (корелювати з conntrack)
cr0x@server:~$ ss -s
Total: 10648 (kernel 0)
TCP: 7342 (estab 1249, closed 5621, orphaned 0, synrecv 18, timewait 5621/0), ports 0
Transport Total IP IPv6
RAW 0 0 0
UDP 211 198 13
Значення: timewait величезний і на рівні сокетів, що відповідає турбулентності conntrack. Часто це проблема поведінки додатка (відсутність keepalive, немає пулінгу), а не ядра.
Рішення: Якщо можна виправити турбулентність у додатку/проксі — зробіть це. Налаштування ядра не замінює здорове повторне використання з’єднань.
Завдання 13: Швидке пом’якшення — негайно підняти max (тимчасово)
cr0x@server:~$ sudo sysctl -w net.netfilter.nf_conntrack_max=524288
net.netfilter.nf_conntrack_max = 524288
Значення: Межа тепер вища. Якщо виснаження був єдиною проблемою — відкиди мають припинитися.
Рішення: Трактуйте це як турнікет. Подальші кроки: налаштування бакетів, перегляд пам’яті і розслідування, чому записи зросли.
Завдання 14: Зробити зміну постійною (Debian sysctl.d)
cr0x@server:~$ sudo sh -c 'cat > /etc/sysctl.d/99-conntrack-tuning.conf <
cr0x@server:~$ sudo sysctl --system | tail -n 5
* Applying /etc/sysctl.d/99-conntrack-tuning.conf ...
net.netfilter.nf_conntrack_max = 524288
Значення: Налаштування переживе перезавантаження і застосовано зараз.
Рішення: Персистуйте лише після перевірки пам’яті та якщо ви не маскуєте шторм трафіку.
Завдання 15: Безпечно налаштувати бакети хешу (опція модуля на час завантаження)
cr0x@server:~$ sudo sh -c 'cat > /etc/modprobe.d/nf_conntrack.conf <
cr0x@server:~$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-6.12.0-amd64
Значення: hashsize встановлюється під час завантаження модуля; на багатьох системах це фактично рішення під час завантаження. Оновлення initramfs застосує зміну на ранньому етапі.
Рішення: Плануйте вікно перезавантаження, якщо потрібні зміни бакетів. Не робіть вигляд, що можна «просто sysctl» у розпал інциденту.
Завдання 16: Знайти очевидні патерни сканування/атаки (SYN, invalid)
cr0x@server:~$ sudo conntrack -S | sed -n '1p'
cpu=0 found=1483921 invalid=121 insert=927314 insert_failed=8421 drop=8421 early_drop=0 error=0 search_restart=0
Значення: Якщо invalid починає різко рости разом з відкидами, ви можете відстежувати сміття: пошкоджені пакети, асиметричну маршрутизацію або частковий DDoS.
Рішення: Розгляньте фільтрацію в апстрімі і локальне обмеження швидкості; збільшення conntrack лише дає зловмисникам більшу іграшку.
Стратегія розмірів, яка не підведе пізніше
Є три важливі регулятори, до яких тягнуться люди:
nf_conntrack_max: максимальна кількість відстежуваних записів.nf_conntrack_buckets(або опція модуляhashsize): бакети хеш-таблиці для пошуків.- Таймаути: як довго записи утримуються, особливо для UDP і напіввідкритих TCP-станів.
Безпечна ментальність налаштування: ємність (max), ефективність (buckets) і утримання (таймаути). Ви можете «вирішити» проблему повної таблиці підвищенням max, але при цьому просто зберігатимете більше сміття, витрачати більше пам’яті й уповільнити пошуки, якщо ігнорувати бакети.
Крок 1: Визначте роль хоста
- Чистий сервер (без NAT, мінімальний стан фаєрволу): conntrack може майже не мати значення. Якщо він повний — щось дивне (неочікуване правило NAT, проксі-сайда або локальна мережа контейнерів).
- Шлюз/NAT-вузол: conntrack центральний. Розмірюйте його за агрегованими клієнтами та їхньою поведінкою. Тут не варто скупитися.
- Вузол Kubernetes: це шлюз у масці. Чекайте сплесків під час rollout-ів, autoscaling і drain-ів вузлів.
Крок 2: Оцініть потрібну кількість записів (практична математика, не фантазія)
Не переускладнюйте. Користуйтеся спостереженими піками і додайте запас:
- Виміряйте
nf_conntrack_countу звичні навантажені періоди. - Виміряйте під час деплоїв/переносів («поганий день»).
- Встановіть
nf_conntrack_maxпринаймні в 2× від 99-го процентиля піку для продакшн-шлюзів, іноді 3×, якщо є шторми повторів.
Якщо не можете виміряти піки, почніть консервативно високо для шлюзів, потім перевірте пам’ять. Вартість бути занадто низьким — відмови. Вартість бути занадто високим — використання пам’яті і потенційне уповільнення пошуків (які можна компенсувати бакетами).
Крок 3: Перевірте запас пам’яті
Записи conntrack живуть у пам’яті ядра (slab). Підвищення nf_conntrack_max збільшує потенційне споживання пам’яті. Розмір запису варіюється від ядра до ядра, тому ставте його як «сотні байт», потім підтверджуйте через slabinfo.
На машині, яка вже ризикує OOM, різке підвищення conntrack — це як купити більший склад, переселившись у кухню.
Таймаути: тихий множник
Таймаути визначають, як довго записи утримуються. Це важливо, бо багато навантажень створюють потоки швидше, ніж ви думаєте, і мала зміна часу утримання може подвоїти або потроїти кількість записів у стані рівноваги.
Які таймаути зазвичай створюють проблеми
- UDP-таймаут занадто великий: поширена практика «щоб бути в безпеці». Утримує мертві UDP-потоки і пожирає таблицю.
- TCP established timeout занадто великий на NAT-шлюзах: може тримати стан клієнтів, що зникли (мобільні клієнти, проблемний Wi‑Fi, аварійні додатки).
- Таймаути напіввідкритих TCP: при скануванні або SYN-флуді ці напіввідкриті записи можуть домінувати.
Жарт №2: Підвищувати таймаути «щоб бути в безпеці» — як зберігати всі запрошення на зустрічі назавжди, бо колись ви можете їх відвідати ретроспективно.
Розумний підхід до таймаутів
Не ставте таймаути випадково, читаючи блоги. Натомість:
- Визначте протокол/стан, що домінує в conntrack.
- Підтвердіть, чи це пов’язано з реальною користю користувача (довгоживучі TCP-сеанси) або з турбулентністю/шумом (сплески DNS, повторы, сканування).
- Підкоригуйте мінімальний набір таймаутів, що зменшать утримання сміття без руйнування легітимних довгоживучих потоків.
У багатьох середовищах найкраще — не гратися з таймаутами, а припинити турбулентність на джерелі: HTTP keepalive, пулінг з’єднань і адекватні бюджети повторів. Conntrack має відстежувати реальні потоки, а не побічний продукт штурму.
Бакети хешу і продуктивність: nf_conntrack_buckets
Навіть якщо ви ніколи не досягнете max, погано налаштована хеш-таблиця може нашкодити. Пошуки conntrack відбуваються в гарячому шляху обробки пакетів; довгі хеш-ланцюги означають додатковий CPU на пакет, що проявляється як затримка і softirq-навантаження.
Що під вашим контролем
nf_conntrack_bucketsчасто доступний лише для читання під час роботи і задається при ініціалізації модуля.- Опція модуля
hashsize=— поширений спосіб встановити її постійно.
Порада, що працює частіше, ніж ні
Загальне операційне співвідношення:
nf_conntrack_max≈ 4 ×nf_conntrack_buckets
Це тримає середню довжину ланцюгів прийнятною. Це не магія, а відправна точка. Якщо ваш трафік має дивні розподіли tuple або ви під атакою — потрібне спостереження.
Особливості Debian 13: sysctl, systemd і збереження налаштувань
Debian 13 поводиться як сучасний Debian: параметри ядра через sysctl, персистентні конфіги під /etc/sysctl.d/, опції модулів під /etc/modprobe.d/ і рання ініціалізація обробляється initramfs.
Що робити в Debian 13
- Помістіть sysctl-параметри conntrack у окремий файл, наприклад
/etc/sysctl.d/99-conntrack-tuning.conf. - Для hashsize встановіть
options nf_conntrack hashsize=...в/etc/modprobe.d/nf_conntrack.confі виконайтеupdate-initramfs -u. - Перезавантажте в вікні обслуговування, щоб надійно застосувати зміни бакетів.
Також: якщо ваш хост використовує контейнери, перевірте, що ваш «простий фаєрвол» не робить таємно NAT для bridge-мереж. Багато хто так робить. Conntrack байдуже, що це «лише для розробки».
Три короткі корпоративні історії з реального життя
Коротка історія 1: Інцидент через неправильне припущення
Компанія мала Debian-крайову шар: кілька хостів із зворотним проксі й кількома правилами фаєрволу для комфорту. Ніякого NAT, ніякого VPN, нічого складного. Вони були впевнені, що conntrack не важливий, бо «ми не маршрутизатор».
Потім прийшла нова політика безпеки: stateful default-deny з широкими дозволами «established/related». З правилами все було правильно, і вони дійсно зупинили деякий небажаний трафік. Але це також зробило conntrack обов’язковим для практично всіх вхідних потоків.
Через кілька тижнів пройшла маркетингова кампанія. Збільшилась турбулентність з’єднань — багато коротких TLS-рукопотискань через агресивні клієнти і неправильні keepalive. На піку журнал ядра почав кричати про conntrack table full. Проксі виглядав «здоровим» за CPU, і мережна команда звинуватила апстрім. Тим часом нові користувачі не могли підключитися, але існуючі сесії трималися, що зробило проблему частковою відмовою.
Неправильне припущення було не в тому, що «conntrack поганий». Неправильним було припущення «conntrack лише для NAT». На stateful-фаєрволі conntrack — це продукт.
Виправлення: вони підвищили nf_conntrack_max із гідним запасом, налаштували hashsize відповідно і — що важливіше — виправили keepalive і повторне використання з’єднань у проксі. Після цього лічильник conntrack стабілізувався на частці від max, і «випадкові» відмови зникли.
Коротка історія 2: Оптимізація, що обернулась проти них
Платформна команда хотіла зменшити втрати для UDP-телеметрії і вирішила «уникнути відкидів», підвищивши UDP-таймаути conntrack. Зміна була розгорнута по набору вузлів Debian 13, які виступали NAT-шлюзами для філій і контейнерних навантажень. Ніхто не робив огляд ємності, бо на вузлах було багато RAM і «це ж просто таймаут».
Довгий час виглядало нормально. Потім звичайне депло привело до дрібного brownout’у в колекторі даних. Клієнти повторювали. UDP-потоки створювалися знову й знову. Довший таймаут утримував записи ширше, тож conntrack таблиця наповнилася мертвими розмовами, що ніколи не отримають відповіді. Нові потоки почали відмовляти, що спричинило ще більше повторів і ще більше потоків. Класична позитивна петля зворотного зв’язку.
Вони намагалися підняти nf_conntrack_max в інциденті, що трохи допомогло, але збільшило CPU через погане налаштування бакетів і довші ланцюги пошуку. Результат — «менше поламано, але повільніше», що не виглядає перемогою.
Провал полягав не в ідеї налаштування, а в налаштуванні без вимірювання турбулентності і розуміння, що час утримання визначає стійку зайнятість таблиці. Правильне вирішення: скасувати підвищення UDP-таймауту, зменшити повтори на клієнті і додати зворотний тиск у каналі. Після цього помірно підняли conntrack max з відповідними бакетами на основі виміряних піків.
Коротка історія 3: Скучний, але правильний підхід, що врятував ситуацію
Інша організація мала політику: кожен шлюзовий хост мав «дашборд ємності ядра» з трьома нудними лініями: nf_conntrack_count, nf_conntrack_max і використання slab для nf_conntrack. Жодної складної SLO-математики. Просто базова інформація і алерт при 70% стійкого навантаження.
Під час збою постачальника їхні сервіси почали агресивно повторювати вихідні HTTPS-виклики. Це проблема клієнта, але вона проявилася як турбулентність потоків на NAT-вузлі. Їхній alert conntrack спрацював раніше, ніж клієнти помітили щось. На черговому — побачили зростання count, підтвердили домінування SYN_SENT і обмежили клас задач з повторними викликами. Вони також тимчасово підняли conntrack max, бо мали заздалегідь порахований запас пам’яті і документований «безпечний діапазон» для підйому.
Ніяких героїчних дій, жодної війни. Тікет інциденту був майже незручним: «Запобігли виснаженню conntrack, обмеживши повтори; налаштували max у плановому діапазоні.» Оце та нудна практика, яку хочеться бачити в продакшні.
Рятівна практика була не в секретному прапорі ядра, а в спостережуваності ємності, заздалегідь погоджених межах налаштувань і культурі ставлення до повторів як до продукційного трафіку, а не як до безкоштовної терапії для збійних залежностей.
Поширені помилки: симптом → корінь проблеми → виправлення
1) «Деякі з’єднання працюють, нові відмовляють» → conntrack повний → підняти max і зупинити турбулентність
Симптоми: Існуючий SSH залишається живим, але нові SSH/HTTP підключення зависають. У журналах ядра видно відкиди.
Корінь проблеми: Таблиця досягла nf_conntrack_max. Нові потоки не можуть бути відстежені.
Виправлення: Негайно: тимчасово підняти nf_conntrack_max. Потім знайти джерело турбулентності і виправити keepalive/повтори; налаштувати бакети, якщо залишаєте вищий max.
2) «Ми підняли max, але стало повільно» → занадто мало бакетів → задати hashsize і перезавантажити
Симптоми: Відкиди зупинилися, але латентність зросла і CPU у softirq піднявся.
Корінь проблеми: Ви підняли max без збільшення бакетів, що спричинило довгі хеш-ланцюги і повільні пошуки.
Виправлення: Задайте опцію модуля hashsize (або налаштуйте бакети, якщо підтримується), потім перезавантажте в запланований період.
3) «Трапляється лише під час деплоїв» → шторми повторів + короткоживучі потоки → виправити поведінку клієнтів
Симптоми: Під час rollout-ів або failover-ів лічильник conntrack пікує.
Корінь проблеми: Турбулентність з’єднань через повтори, агресивні health checks або стрибуче сервісне виявлення.
Виправлення: Зменшіть повтори, додайте джиттер, увімкніть пулінг з’єднань і зробіть health checks менш агресивними. Потім розмірюйте conntrack під реалістичний пік.
4) «UDP пожирає все» → таймаути UDP занадто великі або шум у трафіку → налаштуйте UDP і відфільтруйте шум
Симптоми: Conntrack домінують UDP-записи; часто виникають помилки DNS.
Корінь проблеми: Висока турбулентність UDP при довгому утриманні записів, можливо сканування або телеметричний шум.
Виправлення: Зробіть таймаути UDP розумними, зменшіть fan-out телеметрії і відфільтруйте явне сміття на краю мережі, коли це доречно.
5) «Почалося після увімкнення Docker/Kubernetes» → прихований NAT і правила iptables → сприймайте вузол як шлюз
Симптоми: «Звичайний сервер» раптово досягає лімітів conntrack після встановлення runtime контейнерів.
Корінь проблеми: Контейнерна мережа додає NAT/форвардинг і stateful-правила, що збільшує кількість відстежуваних потоків.
Виправлення: Проведіть інвентаризацію правил NAT, потім налаштуйте conntrack відповідно. Розгляньте виділені шлюзи для виходу для важких навантажень.
6) «conntrack invalid величезний» → асиметрична маршрутизація або проблеми offload → виправте маршрути/шляхи
Симптоми: Високі показники invalid, дивні відкиди, іноді не працює лише один напрямок.
Корінь проблеми: Трафік повертається іншим шляхом, ніж пішов (асиметрична маршрутизація), або пакети обходять очікування відстеження через offload/topology.
Виправлення: Виправте симетрію маршрутизації або змініть архітектуру так, щоб stateful-відстеження було на послідовному шляху. Уникайте «пластирів», що просто розширюють conntrack.
Контрольні списки / покроковий план
Контрольний список: під час активного інциденту (15–30 хвилин)
- Підтвердьте в журналах
nf_conntrack: table fullі що count дорівнює max. - Отримайте швидкий розподіл за протоколом/станом (TCP vs UDP; SYN_SENT vs ESTABLISHED).
- Перевірте, чи цей хост робить NAT (nftables/iptables NAT chains).
- Застосуйте тимчасове підвищення max, якщо є запас пам’яті.
- Обмежте найбільше джерело турбулентності (повторювані задачі, злі клієнти, некоректні health checks).
- Зберіть короткий пакет доказів для аналізу пізніше: значення sysctl, зведення conntrack, топ-призначень.
Контрольний список: після стабілізації (той самий день)
- Визначте роль хоста: шлюз/NAT, вузол k8s, чи чистий сервер.
- Встановіть постійний
nf_conntrack_maxна основі виміряних піків плюс запас. - Заплануйте налаштування бакетів/hashsize у відповідності з новим max; сплануйте перезавантаження.
- Перегляньте таймаути; відкоти будь-які «на всякий випадок» підвищення, що збільшують утримання.
- Виправте турбулентність у джерелі: keepalive, пулінг, бюджети повторів, backoff/jitter.
- Додайте алерти при 70–80% стійкого використання і панель для count/max/slab.
Контрольний список: довгострокове зміцнення (цей квартал)
- Тестуйте ємність на турбулентність з’єднань, а не лише на пропускну здатність. Включіть сценарії деплоїв і failover.
- Документуйте безпечний аварійний діапазон для
nf_conntrack_maxна основі запасу пам’яті. - Якщо ви запускаєте Kubernetes, ставте conntrack як вузлове SLO-залежність; розмірюйте по типах вузлів.
- Розгляньте переміщення важкого NAT/egress на виділені шлюзи, щоб ізолювати площу ураження.
- Аудит правил фаєрволу на предмет непотрібного відстеження (обережно; не ламаючи stateful-безпеку).
Питання й відповіді
1) Чи означає «nf_conntrack table full», що мої правила фаєрволу неправильні?
Ні. Зазвичай це означає, що ваші правила працюють як задумано (stateful), але таблиця стану замала для поточного патерну трафіку або таймаутів.
2) Чи можу я просто встановити nf_conntrack_max дуже великим і забути?
Можете, але платитимете пам’яттю ядра і потенційно CPU (особливо якщо бакети не підібрані). Також велика таблиця дозволить скануванням/атакам займати більше стану до моменту, поки ви помітите проблему.
3) Як зрозуміти, чи NAT є причиною?
Шукайте правила masquerade/SNAT в nftables або iptables NAT-таблицях і підтвердіть, що хост форвардить трафік для інших клієнтів або контейнерів. NAT майже завжди збільшує тиск на conntrack.
4) Чому DNS-помилки з’являються першими?
DNS — це UDP, короткоживуче й чутливе до латентності. Коли нові UDP-потоки відкидаються, клієнти повторюють і ампліфікують турбулентність. Часто це перша видима тріщина.
5) Яка різниця між nf_conntrack_buckets і nf_conntrack_max?
nf_conntrack_max — це ємність (скільки записів). Бакети визначають продуктивність пошуку. Великий max з замалою кількістю бакетів збільшує вартість CPU на пакет.
6) Чи відпадають встановлені TCP-з’єднання, коли таблиця повна?
Зазвичай ні, одразу — бо для них уже є записи. Більшість болю відчувають нові з’єднання і трафік, що потребує нового NAT-мапінгу.
7) Чи можу я вимкнути conntrack для частини трафіку?
Іноді так, для специфічних потоків, де відстеження не потрібне. Але це легко зламати NAT, очікування stateful-фаєрволу і відповідний трафік. Робіть це лише коли розумієте шлях пакетів і маєте тести.
8) Це проблема iptables чи nftables?
Ні й так. iptables/nftables — це фронтенди для правил; conntrack — підсистема ядра, на яку вони покладаються. Міграція на nftables не зніме тиск на conntrack автоматично.
9) Що якщо conntrack_count не біля max, але я все одно бачу відкиди?
Подивіться conntrack -S на insert failures, перевірте розмір бакетів і чи не маєте ви коротких сплесків, що призводять до тимчасового виснаження або проблем з пам’яттю. Також перевірте, чи журнали актуальні, а не старі.
10) Чи вимагає підвищення nf_conntrack_max перезавантаження?
Ні, nf_conntrack_max можна змінити за runtime через sysctl. Зміни бакетів/hashsize зазвичай потребують перезавантаження модуля або перезавантаження системи, щоб застосувати їх безпечно.
Наступні кроки, які ви реально можете зробити цього тижня
Робіть це в порядку, і ви перетворите conntrack з несподіваної відмови на керований метрик ємності:
- Додайте видимість: графічно відображайте
nf_conntrack_count,nf_conntrack_maxі використання slab conntrack. Алертуйте при стійких 70–80%. - Класифікуйте вузли: будь-що, що робить NAT або використовує контейнерну мережу — це шлюз. Тримайтеся цього підходу.
- Виберіть адекватний max: базуйтеся на спостережуваних піках із запасом; персистуйте через
/etc/sysctl.d/. - Зрівняйте бакети з max: задайте опцію модуля
hashsize, оновіть initramfs і заплануйте вікно перезавантаження. - Виправляйте турбулентність: зменшуйте повтори, додавайте джиттер, увімкніть keepalive/пулінг і припиніть перетворювати тимчасові відмови в потоки трафіку.
- Перегляньте таймаути: відкочуйте «на всякий випадок» підвищення; налаштовуйте лише на підставі даних і з урахуванням довгоживучих з’єднань.
Conntrack — це спільна таблиця ядра. Ставтеся до неї як до дискового простору бази даних: кінцевий, вимірюваний і здатний зіпсувати вам день, якщо його ігнорувати.