Перервні (інтермітентні) втрати пакетів — найгірший тип інциденту: вони уникають графіків, ховаються під час нарад з інциденту і з’являються лише коли ваш CEO приєднується до відеозустрічі. Команда застосунку каже «мережа». Мережна команда каже «сервери». Хтось пропонує перезавантажити «щоб почистити».
Ось продакшн-процес, що припиняє суперечки: ви доводите, де пакети губляться, використовуючи конкретні лічильники та захоплення в Linux, а потім виправляєте вузьке місце, яке справді відповідає за втрати. Не за відчуттями — за доказами.
Жорстка ментальна модель: де відбуваються втрати
«Втрата пакета» — це симптом, а не місце. Пакет може бути викинутий у багатьох місцях, і Linux дає вам лічильники для більшості з них. Трюк у тому, щоб знати, які лічильники є сусідніми до домену втрат, який ви досліджуєте.
Думайте в термінах доменів втрат, а не інструментів
Коли люди застрягають, вони зазвичай обирають інструмент (ping, traceroute, tcpdump) і продовжують його запускати інтенсивніше. Інструменти — ок. Але правильний порядок: визначити домен, потім підібрати мінімальний набір інструментів, щоб його довести.
Поширені домени втрат у production на Linux:
- Віддалені втрати: пакет виходить із вашого хоста нормально, але гине далі (комутатор, маршрутизатор, фаєрвол, черга вхідного обробника на віддаленому хості, CPU віддаленого хоста, політика).
- Проблеми на лінку: кабелі, оптика, флапи, FEC, PCS-помилки. Це «фізичне», але проявляється як MAC/PHY лічильники і інколи логи драйвера.
- Втрати на шляху прийому NIC: переповнення кільця, нестача дескрипторів, баги драйвера або взаємодії з офлоадами.
- Втрати в чергах ядра: NAPI/softirq беклог (класична історія
softnet_stat), голодування CPU, маршрутизація переривань. - Netfilter/conntrack: тиск на таблицю станів, недійсні стани, агресивні таймаути або правила, що відкидають під навантаженням.
- qdisc/контроль трафіку: shaping/policing, поведінка fq_codel, або добре намірений qdisc, що тихо ріже пакети.
- Втрати на рівні сокета: додаток не читає, занадто малий receive buffer, переповнення accept-черги, проблеми з SYN backlog.
- Віртуалізація/оверлей: черги veth, скидання на bridge, наклад VXLAN/Geneve, невідповідність MTU при інкапсуляції.
- «Мережеві» втрати через зберігання: не жарт — якщо додаток блокується на диску, він припиняє читати сокети і ви «бачите» втрати як ретрансміти й таймаути.
Мета не в тому, щоб зібрати кожен можливий метрік. Мета — зіставити один спостережуваний симптом (ретрансміти, розриви, хвостова латентність, таймаути) з одним конкретним лічильником, що зростає в одному місці.
Два типи «тільки інколи»
Інтермітентні втрати зазвичай потрапляють в одну з двох категорій:
- Сплескові втрати (microbursts): усе ок, поки раптом ні, і тоді невелика черга переповнюється. Графіки виглядають чистими, бо середні значення ховають піки.
- Умовні втрати: лише певний трафік підпадає під вплив (певний MTU, DSCP, потоки, що хешуються на пошкодженому члені LACP, один IRQ прив’язаний до зайнятого CPU, один conntrack-бакет під атакою).
Якщо не розрізняти ці типи, ви будете дебажити не те роками. Сплескові втрати вимагають роботи з чергами/пропускною спроможністю. Умовні втрати вимагають інспекції хешування, MTU, політик і аналізу по потоках.
Цитата, яку варто тримати на стікері: «Надія — не стратегія.»
— парафраз ідеї, яку часто приписують інженерним лідерам в операціях.
Жарт №1: Втрата пакета — як дитина з маркером. Якщо не спіймаєш її на гарячому, у підсумку отримуєш стіну з «хм, дивно».
Швидкий план діагностики (перший/другий/третій)
Це порядок триажу, що дозволяє швидко знайти вузьке місце, навіть коли проблема інтермітентна, а ваші дашборди брешуть через усереднення.
Перший: доведіть, локальні втрати чи віддалені
- Перевірте TCP ретрансміти й лічильники drops ядра на постраждалому хості. Якщо ретрансміти ростуть, але локальні RX/TX drops — ні, підозрюйте upstream, віддалені ресурси або middlebox-и.
- Захопіть трафік по обидва боки межі інтерфейсу. Наприклад: захоплення на
eth0і наbond0, або наeth0і всередині неймспейсу. Якщо пакет видно з одного боку, але не з іншого — ви знайшли межу втрат. - Порівняйте лічильники NIC/PHY. CRC, FCS, symbol errors і флапи лінка — це не «проблема додатку».
Другий: перевірте три черги, що найчастіше переповнюються
- NIC RX ring / драйверні дропи:
ethtool -Sчасто показує «missed», «no_buffer», «rx_missed_errors» тощо. - Беклог ядра:
/proc/net/softnet_stat— сигнатура для голодування CPU/softirq. - qdisc:
tc -s qdiscпоказує дропи на egress; policing теж виглядає як дропи.
Третій: ізолюйте умовні патерни
- MTU/фрагментація: перевірте PMTUD blackhole-и, оверлейний оверхед і фільтрацію ICMP.
- Хешування/LACP: чи має один член помилки? Чи є асиметричний маршрут або політика поліцингу?
- conntrack: таблиця заповнена або сильне «churn»; дропи з’являються «лише під піком».
- IRQ/прив’язка CPU: один зайнятий керн обробляє весь RX — отже інтермітентні дропи під навантаженням.
Якщо виконувати кроки в такому порядку, ви припините гадати. Також припините «фіксити» те, що не було зламано.
Цікаві факти та історичний контекст
- Ethernet завжди інколи кидав фрейми під заторами; ранній спільний Ethernet покладався на детекцію колізій. Сучасні свічі перемістили біль до буферів і черг.
- Linux NAPI був введений, щоб зменшити шторм переривань, переключившись на опитування під навантаженням; тому час softirq так важливий на завантажених NIC.
- Bufferbloat став мейнстрімним терміном наприкінці 2000-х; великі буфери зменшують втрати, але руйнують латентність. Цей компроміс і досі живе в NIC і свічах.
- TCP congestion control припускає, що втрата означає затори. Коли втрата спричинена поганою оптикою або пошкодженою чергою, TCP все одно відкотиться і ваш додаток «таємниче сповільниться».
- GRO/LRO офлоади були створені, щоб зменшити CPU-навантаження, з’єднуючи пакети, але вони можуть ускладнити захоплення та аналіз часу пакетів.
- fq_codel та пов’язані qdisc-и стали популярними, бо борються з латентністю під навантаженням, керуючи чергами розумніше, ніж FIFO.
- Conntrack існує, бо stateful фаєрволи та NAT потребували відстеження; у масштабі conntrack стає спільним ресурсом ядра, що може впасти, як база даних.
- RSS/RPS/XPS (Receive/Transmit packet steering) — це десятиліття роботи, щоб забезпечити рівномірну подачу пакетів на багатоядерні CPU; неправильна конфігурація і досі викликає «одне ядро плавиться, пакети падають».
- Jumbo frames не нові, але оверлеї зробили помилки MTU простішими: VXLAN/Geneve оверхед перетворює «працює в лабораторії» на «втрачається лише при великих payload-ах».
Практичні завдання: команди, виводи, рішення
Нижче — реальні завдання, які ви можете виконати під час інциденту. Кожне містить: команду, що означає вивід, і яке рішення з нього випливає. Запускайте їх на обох кінцях, коли можете. Якщо запустите лише на одному хості — багато дізнаєтесь, але не достатньо, щоб виграти суперечку.
Завдання 1: Підтвердіть, що симптом реальний (і який протокол його показує)
cr0x@server:~$ ping -c 20 -i 0.2 -s 56 10.10.5.20
PING 10.10.5.20 (10.10.5.20) 56(84) bytes of data.
64 bytes from 10.10.5.20: icmp_seq=1 ttl=62 time=0.611 ms
64 bytes from 10.10.5.20: icmp_seq=2 ttl=62 time=0.623 ms
Request timeout for icmp_seq 7
64 bytes from 10.10.5.20: icmp_seq=8 ttl=62 time=0.640 ms
--- 10.10.5.20 ping statistics ---
20 packets transmitted, 19 received, 5% packet loss, time 3805ms
rtt min/avg/max/mdev = 0.611/0.655/0.812/0.052 ms
Значення: ICMP-втрати є, але ICMP може бути деприоритизований або обмежений за швидкістю пристроями. Не робіть висновку «мережа ломиться» лише за ping.
Рішення: Негайно перевірте сигнали на рівні TCP (ретрансміти) для реальних робочих навантажень. Якщо тільки ICMP падає — підозрюйте поліцинґ/ліміти швидкості.
Завдання 2: Перевірте TCP ретрансміти та скидання на хості
cr0x@server:~$ netstat -s | egrep -i 'retran|reset|timeout' | head
1823 segments retransmitted
17 bad segments received
42 resets received for embryonic SYN_RECV sockets
9 connections reset due to unexpected data
Значення: Ретрансміти вказують на втрати десь по дорозі (або настільки сильне реупорядкування, що виглядає як втрата). SYN_RECV resets натякають на тиск backlog або проблеми з обробкою SYN.
Рішення: Якщо ретрансміти зростають під час інциденту — вважайте це реальною втратою пакетів або екстремальним джиттером. Перейдіть до лічильників і захоплень.
Завдання 3: Визначте маршрут і чи має працювати PMTUD
cr0x@server:~$ ip route get 10.10.5.20
10.10.5.20 via 10.10.4.1 dev eth0 src 10.10.4.55 uid 0
cache
Значення: Тепер ви знаєте egress-інтерфейс і наступний хоп. Це ваша анкера для всіх наступних лічильників і захоплень.
Рішення: Запустіть interface-level stats на eth0. Якщо маршрут змінюється під час проблеми (ECMP), доведеться корелювати поведінку по кожному шляху.
Завдання 4: Перевірте стан лінка, швидкість/дуплекс і очевидні фізичні проблеми
cr0x@server:~$ ethtool eth0
Settings for eth0:
Supported ports: [ FIBRE ]
Supported link modes: 10000baseSR/Full
Speed: 10000Mb/s
Duplex: Full
Auto-negotiation: off
Link detected: yes
Значення: Лінк піднятий на очікуваній швидкості. Це не відкидає оптику або кабель повністю, але прибирає зі списку «duplex mismatch» і «насправді 1G».
Рішення: Якщо лінк флапає або домовляється на неочікуваній швидкості — зупиніться і виправте фізичну проблему. Якщо виглядає стабільно — рухайтесь до лічильників помилок.
Завдання 5: Зчитайте лічильники NIC і драйвера для RX/TX дропів та помилок
cr0x@server:~$ ethtool -S eth0 | egrep -i 'drop|error|miss|no_buffer|timeout' | head -n 20
rx_missed_errors: 1249
rx_no_buffer_count: 1180
rx_errors: 0
tx_errors: 0
tx_timeout_count: 0
Значення: rx_missed_errors / rx_no_buffer_count зазвичай означають, що NIC не зміг передати пакети в ядро досить швидко (виснаження кільця, голодування CPU або проблеми драйвера). Це локальні втрати.
Рішення: Якщо ці лічильники ростуть під час інциденту — дивіться на тиск на шлях прийому: softnet_stat, розподіл IRQ і розміри кільця.
Завдання 6: Перевірте загальні дропи інтерфейсу (менш точні, але корисні)
cr0x@server:~$ ip -s link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 3c:fd:fe:aa:bb:cc brd ff:ff:ff:ff:ff:ff
RX: bytes packets errors dropped missed mcast
9132299123 9023123 0 431 0 12213
TX: bytes packets errors dropped carrier collsns
8023312288 8112231 0 0 0 0
Значення: Поле dropped — грубий агрегат; воно може включати дропи на рівні ядра, а не лише NIC. Проте: якщо воно зростає разом з проблемою — це важлива підказка.
Рішення: Якщо RX dropped зростає, але ethtool -S не показує misses — підозрюйте брак в беклозі ядра, netfilter або qdisc/рівні віртуалізації.
Завдання 7: Перевірте дропи беклогу ядра через softnet_stat
cr0x@server:~$ awk '{d+=$2; t+=$1} END{print "total_processed="t, "total_dropped="d}' /proc/net/softnet_stat
total_processed=140338812 total_dropped=92841
Значення: Другий стовпець — це кількість дропів у per-CPU беклозі. Якщо це число швидко зростає під час інциденту — ядро відкидає пакети ще до того, як вони дійдуть до сокета.
Рішення: Дивіться на завантаження CPU, афінність переривань і чи NIC годує одне ядро. Фізичні правки не допоможуть — треба виправляти CPU/IRQ/черги.
Завдання 8: Визначте, чи IRQ сконцентровано на одному CPU
cr0x@server:~$ grep -E 'eth0|mlx|ixgbe|i40e' /proc/interrupts | head
86: 9833221 12 4 9 IR-PCI-MSI 524288-edge eth0-TxRx-0
87: 31 9123312 8 11 IR-PCI-MSI 524289-edge eth0-TxRx-1
88: 25 18 9011123 13 IR-PCI-MSI 524290-edge eth0-TxRx-2
89: 22 15 10 8832212 IR-PCI-MSI 524291-edge eth0-TxRx-3
Значення: Якщо одна лінія IRQ має майже всі переривання на одному CPU — під навантаженням ви отримаєте локальні дропи. Рівномірний розподіл — мета, але «рівномірність» залежить від NUMA і робочого навантаження.
Рішення: Якщо спотворення є, акуратно налаштуйте IRQ affinity, увімкніть/перевірте RSS і підтвердіть RPS/XPS там, де доречно.
Завдання 9: Перевірте час CPU в softirq (мережева обробка)
cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0-18-generic (server) 02/04/2026 _x86_64_ (32 CPU)
02:18:11 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
02:18:12 PM all 8.2 0.0 6.1 0.2 0.0 14.9 0.0 0.0 0.0 70.6
02:18:12 PM 7 3.1 0.0 5.9 0.0 0.0 62.2 0.0 0.0 0.0 28.8
Значення: Ядро з дуже високим %soft свідчить, що воно тоне в обробці пакетів. Це сильно корелює з дропами softnet_stat.
Рішення: Перерозподіліть переривання, перевірте кількість RSS-черг, зменшіть наклад на пакет (офлоади можуть допомогти) або розподіліть трафік.
Завдання 10: Проінспектуйте дропи qdisc і backlog на egress
cr0x@server:~$ tc -s qdisc show dev eth0
qdisc fq_codel 0: root refcnt 2 limit 10240p flows 1024 quantum 1514 target 5.0ms interval 100.0ms memory_limit 32Mb ecn
Sent 8122331123 bytes 8112231 pkt (dropped 3312, overlimits 0 requeues 12)
backlog 0b 0p requeues 12
maxpacket 1514 drop_overlimit 3312 new_flow_count 4012 ecn_mark 0
Значення: Дропи тут — це дропи egress-черги на хості. Це не «мережа»; це ваш сервер, який вирішив, що не може поставити більше пакетів в чергу.
Рішення: Визначте, чому хост забитий на egress: shaping/policing, занадто малий ліміт qdisc, або NIC не встигає відправляти (або блокується flow control).
Завдання 11: Виявіть невідповідність MTU і PMTUD blackholes
cr0x@server:~$ ping -M do -s 1472 -c 3 10.10.5.20
PING 10.10.5.20 (10.10.5.20) 1472(1500) bytes of data.
ping: local error: message too long, mtu=1500
ping: local error: message too long, mtu=1500
ping: local error: message too long, mtu=1500
--- 10.10.5.20 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2025ms
Значення: MTU цього інтерфейсу — 1500, а ви намагаєтесь відправити 1500-байтовий пакет з DF встановленим. Помилка локальна й очікувана.
Рішення: Тепер виконайте той самий тест з найбільшим очікуваним payload для вашого оверлею або Jumbo. Якщо деякий шлях не може пропустити його й ICMP фільтрується — ви отримаєте «втрати лише при великих пакетах».
Завдання 12: Підтвердіть офлоади й зрозумійте тонкощі захоплень
cr0x@server:~$ ethtool -k eth0 | egrep -i 'gro|gso|tso|lro|rx-checksumming|tx-checksumming'
rx-checksumming: on
tx-checksumming: on
tcp-segmentation-offload: on
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off
Значення: З увімкненими GRO/GSO/TSO захоплення можуть показувати «гігантські» пакети або дивні патерни сегментації. Це не означає, що Jumbo frames увімкнені; це означає, що ядро оптимізує обробку.
Рішення: Не вимикайте офлоади як перший крок. Якщо потрібно тестувати — робіть це тимчасово і лише після збору базових лічильників. Вимкнення офлоадів може підвищити CPU і створити втрати.
Завдання 13: Захоплюйте в правильному місці й у правильний час (і тримайте зріст маленьким)
cr0x@server:~$ sudo tcpdump -i eth0 -nn -s 96 -w /tmp/edge.pcap 'host 10.10.5.20 and (tcp or icmp)' -c 20000
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 96 bytes
20000 packets captured
20000 packets received by filter
0 packets dropped by kernel
Значення: «0 packets dropped by kernel» означає, що процес захоплення не відставав. Добре. Якщо tcpdump втрачає пакети — ваше захоплення стає недостовірним для аналізу мікрошипів.
Рішення: Якщо ви бачите втрати в додатку, але tcpdump показує безперервність на egress — ви, ймовірно, маєте віддалені дропи або проблеми з шляхом назад. Захопіть і на приймальній стороні також.
Завдання 14: Використайте ss для перевірки тиску на сокети (accept queue, rmem/wmem)
cr0x@server:~$ ss -s
Total: 1789 (kernel 0)
TCP: 912 (estab 501, closed 330, orphaned 0, timewait 309/0), ports 0
Transport Total IP IPv6
RAW 0 0 0
UDP 71 60 11
TCP 582 421 161
INET 653 481 172
FRAG 0 0 0
Значення: Це саніті-перегляд. Для глибшої діагностики інспектуйте конкретні лістенери та їх черги.
cr0x@server:~$ ss -lntp | head
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 512 4096 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=1412,fd=8))
LISTEN 128 128 127.0.0.1:9100 0.0.0.0:* users:(("node_exporter",pid=1201,fd=3))
Значення: Recv-Q на лістенері — це backlog очікуваних з’єднань; якщо він постійно на/біля Send-Q (конфігурований backlog), ви втрачаєте SYN або accept застрягає.
Рішення: Якщо ваш лістенер насичений, втрати пакетів можуть бути побічним продуктом (ретраїв/таймаутів), а не справжніми мережевими дропами. Виправте швидкість accept в додатку, налаштуйте backlog або масштабуйте.
Завдання 15: Перевірте насичення conntrack (серед середовища з stateful firewall/NAT)
cr0x@server:~$ sudo sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_count = 252118
net.netfilter.nf_conntrack_max = 262144
Значення: Ви близькі до ліміту. Коли conntrack повний, нові з’єднання можуть падати способом, що виглядає як втрата пакетів (SYN зникає, клієнти повторюють спроби, таймаути).
Рішення: Якщо під час інцидентів значення близьке до max — підвищуйте ліміт (і пам’ять), зменшуйте churn або перестаньте відстежувати трафік, що не потребує відстеження.
Завдання 16: Знайдіть ретрансміти по з’єднаннях (не звинувачуйте всю мережу)
cr0x@server:~$ ss -ti dst 10.10.5.20 | head -n 30
ESTAB 0 0 10.10.4.55:48216 10.10.5.20:443
cubic wscale:7,7 rto:204 rtt:4.2/0.8 ato:40 mss:1460 pmtu:1500 rcvmss:1460 advmss:1460 cwnd:10 bytes_sent:88212 bytes_acked:88120 bytes_received:112233 segs_out:712 segs_in:690 data_segs_out:502 retrans:7/23 lost:0 sacked:8
Значення: Це з’єднання ретрансмить. Тепер можна спитати «що особливого в цьому потоці?» замість звинувачувати весь фабрик.
Рішення: Порівняйте уражені й неуражені потоки: адреса, DSCP, порт, MTU, шлях (ECMP) і чи їде пакет через певного члена бонду.
Жарт №2: Вимикання всіх офлоадів, щоб «спростити», — як виймати сидіння з машини, щоб поліпшити аеродинаміку. Технічно зміна, емоційно задовольняє, операційно підозріло.
Три міні-історії з корпоративного життя
Міні-історія 1: Аутейдж через хибне припущення
Платформна команда успадкувала флот Linux-шлюзів, що виконували NAT для кількох внутрішніх сервісів. Одного тижня почали надходити повідомлення про «випадкові втрати пакетів», що впливали на потоки логіну. Лише інколи. Більше під час піку. Канал інциденту наповнився скриншотами ping, як це заведено.
Хибне припущення: «Якщо ping показує втрати — це мусить бути fabric мережі». Команда ескалувала до мережної групи, яка подивилася помилки інтерфейсу на свічах і не знайшла нічого. Вони відповіли класично: «Тут чисто». Напруга зростала. Хтось запропонував поступовий ребут шлюзів «щоб почистити що завгодно».
Спокійний інженер подивився netstat -s і побачив зростання ретрансмітів. Потім перевірив лічильники conntrack і знайшов таблицю поруч із лімітом. Не завжди повну. Лише фліртувала з ним. Під піком churn нові потоки не створювалися. Деякі клієнти повторювалися з новими портами, додаючи ще більше churn. Замкнене коло, але лише при певних профілях навантаження.
Висновок був банальний: система виросла, розмір conntrack не був відповідно збільшений. Попередній план містив припущення «з’єднання стійкі». Вони такими не були. Оновлення мобільного клієнта збільшило короткоживучі з’єднання. Нічого не було «неправильним» з fabric; шлюз відкидав створення стану і фактично чорнорив SYN-и.
Фікс не був героїчним. Збільшили conntrack max з підходящим запасом пам’яті, перестали відстежувати трафік, що не потребує відстеження, і додали дашборд, що малює nf_conntrack_count проти nf_conntrack_max з алертингом на стійке > 80%.
Урок: інтермітентна «втрата пакетів» може бути проблемою вичерпання стану. Якщо ви не перевірите спільні таблиці ядра на ранньому етапі, витратите час на «дебаг мережі», поки сервер тихо відмовляє запам’ятовувати нові з’єднання.
Міні-історія 2: Оптимізація, що відкотилася
Команда запускала низьколатентний сервіс, суміжний з трейдингом (не високочастотний, але достатньо чутливий, що інженери сперечалися про мікросекунди як про хобі). Вони хотіли зменшити CPU-навантаження на зайнятому вузлі прийому. Хтось запропонував відключити GRO/GSO/TSO, щоб обробка пакетів була «передбачуванішою» і захоплення — «точнішими».
Зміну впровадили в тихий вікно. Використання CPU зросло, але залишалося в межах бюджету. За тиждень трафік зріс. Раптом той самий вузол почав показувати інтермітентні таймаути й ретрансміти. Дашборди були заплутані: пропускна здатність мережі не змінилась, але хвостова латентність стрибнула і клієнтські повтори зросли.
Режим відмови був класичним: вимкнувши офлоади, вони підняли вартість обробки на пакет. Під вищими швидкостями пакетів одне ядро, що обробляло softirq, наситилось. /proc/net/softnet_stat дропи зросли. Ці дропи виглядали як «мережа втрачає пакети», але насправді хост скидкав пакети, бо не встигав.
Команда відкотила зміни офлоадів і натомість вирішила справжню проблему: розподіл IRQ і розміри RX-черг, плюс переконання, що RSS сконфігурований правильно і відображений на відповідні CPU. Захоплення залишилось керованим шляхом вибору правильних меж і snap length.
Урок: «оптимізації», що вимикають функції ядра/NIC, часто просто переміщують витрати в CPU і перетворюють передбачуваний пропуск на інтермітентні втрати. Якщо ви змінюєте офлоади — ви несете відповідальність за побічні ефекти, особливо при наступному рості трафіку.
Міні-історія 3: Нудна практика, що врятувала день
Середня компанія мала непривабливу привычку: вони вели ранбук для триажу мережевих інцидентів, що включав «збирайте ці лічильники до і під час». Він перелічував точні команди — ip -s link, ethtool -S, tc -s qdisc, softnet_stat і невеликий tcpdump-фільтр — і вимагав вставляти виводи в тікет інциденту.
Одного дня запити клієнтів почали таймаутитись, але лише з однієї AZ. Інженери клялися, що це збій деплою, бо час збігався. Ранбук змусив їх зібрати лічильники на непошкодженому й пошкодженому вузлах. Порівняння було вирішальним: на уражених вузлах зростав рахунок RX «missed» в ethtool -S, а на неуражених — ні.
Мережна команда перевірила статистику порту свічу для ураженої шафи і знайшла відповідний патерн фізичного рівня помилок. Недостатньо, щоб флапнути лінк. Достатньо, щоб псувати фрейми і викликати ретрансміти. Фікс був фізичним: заміна оптики і очищення кількох патчкордів. Вирішено без ролбеку, постмортем мав чисту, засновану на доказах хронологію.
Урок: нудне, послідовне збирання лічильників економить час, бо полегшує порівняння. Завдання не в тому, щоб бути кмітливим; завдання — швидко бути правильним.
Поширені помилки: симптом → корінна причина → виправлення
1) «Ping показує 5% втрат, користувачі скаржаться, отже мережа кидає пакети»
Симптом: втрати ping, але TCP-додатки в основному працюють; ICMP RTT шипить.
Корінна причина: ICMP обмежується або деприоритизується на роутерах/фаєрволах; деякі пристрої ставляться до нього як до «недоречності».
Виправлення: перевірте TCP ретрансміти (netstat -s, ss -ti) і метрики додатку; використайте цільовий tcpdump для реального протоколу.
2) «Немає помилок на інтерфейсі, отже це не фізично»
Симптом: спайк ретрансмітів; ip -s link виглядає чистим.
Корінна причина: фізичні проблеми можуть проявлятися в лічильниках свічів, FEC/PCS лічильниках або в vendor-specific NIC stats, що не видно в базових лічильниках.
Виправлення: використайте ethtool -S і корелюйте зі статистикою порту свіча; перевірте логи на flaps.
3) «Ми збільшили буфери, отже дропи зникли»
Симптом: зменшення дропів, але хвостова латентність погіршилась; користувачі все ще скаржаться.
Корінна причина: bufferbloat: менше дропів за рахунок величезних черг і високої латентності.
Виправлення: використовуйте розумні qdisc-и (часто fq_codel), правильно підбирайте розміри буферів і слідкуйте за p99 латентністю як за критичною метрикою.
4) «Тільки великі аплоади падають; малі запити успішні»
Симптом: малі пакети ок; великі трансфери стають, ретрансміти ростуть.
Корінна причина: MTU/PMTUD blackhole, часто через блокування ICMP fragmentation-needed, особливо з оверлеями.
Виправлення: підтвердіть path MTU з ping -M do; забезпечте коректний MTU end-to-end; дозволіть необхідні ICMP; налаштуйте MTU оверлею.
5) «NIC shows zero drops, отже хост не відкидає»
Симптом: ретрансміти і таймаути; ethtool -S виглядає чистим.
Корінна причина: дропи відбуваються в беклозі ядра (softnet_stat), qdisc (tc -s qdisc), netfilter або в чергах сокетів.
Виправлення: перевірте /proc/net/softnet_stat, tc qdisc stats і черги ss; виправляйте розподіл CPU/IRQ і обмеження черг.
6) «Ми вимкнули офлоади для дебагу, і стало гірше»
Симптом: нові дропи під навантаженням; CPU піднімається; softirq високий.
Корінна причина: видалення офлоадів підвищує CPU-вартість на пакет і може спричинити дропи беклогу.
Виправлення: відкотіть зміни офлоадів; дебажте, використовуючи захоплення на межах; замість цього виправляйте масштабування переривань і черг.
7) «Це мусить бути фаєрвол; додамо правила потім»
Симптом: інтермітентні збої з’єднань під піком.
Корінна причина: насичення conntrack або churn, плюс важкі набори правил, що створюють CPU-навантаження.
Виправлення: перевірте використання conntrack; зменшіть відстежуваний трафік, де безпечно; налаштуйте таймаути; переконайтесь, що фаєрвол має метрики й масштаб.
8) «Bonding дає резервування, отже не може бути причиною втрат»
Симптом: інтермітентні втрати лише для деяких потоків; один член має підозру.
Корінна причина: дисбаланс LACP, пошкоджений кабель/оптика на одному члені або хешування, що прив’язує певні потоки до деградованого лінка.
Виправлення: перевірте статистику по членах; тимчасово злийте/видаліть підозрілий член; налаштуйте політику хешування за потреби.
Чеклісти / покроковий план
Чекліст A: Під час інциденту (15–30 хвилин)
- Визначте симптом у термінах протоколу. Це ICMP-втрата, TCP-ретрансміти, UDP-прогалини чи таймаути додатку?
- Зафіксуйте шлях. Запустіть
ip route get, щоб визначити egress-інтерфейс і наступний хоп. - Зберіть базові лічильники негайно. Запустіть:
ip -s link show dev <if>ethtool -S <if>tc -s qdisc show dev <if>awk ... /proc/net/softnet_statnetstat -sабоss -s
- Почекайте 60 секунд і зберіть знову. Дельти важливіші за абсолютні числа.
- Захопіть цільовий трафік на короткий проміжок. Невеликий snaplen, вузький фільтр, фіксований обсяг, запишіть на диск.
- Корелюйте один симптом з одним лічильником. Якщо не можете — ви ще не знаєте, де саме відбуваються втрати.
Чекліст B: Якщо пахне CPU/softirq тиском
- Перевірте дельти
/proc/net/softnet_statпід час проблеми. - Перевірте
mpstatна наявність високого%softна одному/декількох ядрах. - Перевірте
/proc/interruptsна спотворений розподіл IRQ. - Перевірте кількість RSS-черг і чи драйвер експонує multiple queues.
- Лише потім розглядайте розміри кільця, офлоади і тонке налаштування sysctl. Уникайте хаотичних змін.
Чекліст C: Якщо пахне MTU / оверлеєм
- Підтвердіть MTU інтерфейсу:
ip link show. - Перевірте розміри payload-ів з
ping -M doна обох кінцях. - Перевірте, чи фільтрується ICMP у вашому середовищі (безпекові команди люблять це робити «для безпеки»).
- Підтвердіть налаштування MTU оверлею (VXLAN/Geneve) і переконайтесь, що андерлей їх підтримує.
- Виправте MTU послідовно; не покладайтеся на фрагментацію в сучасному продакшні, якщо вам не подобаються сюрпризи.
Чекліст D: Якщо пахне state tables (conntrack) або політикою
- Перевірте використання conntrack через sysctl і спостерігайте під час піку.
- Огляньте лічильники фаєрволу (nftables/iptables) якщо доступні; дропи з відповідними правилами не «таємничі».
- Зменшіть відстежуваний трафік там, де безпечно (наприклад, не весь трафік потребує стану).
- Правильно підберіть розмір таблиці з запасом пам’яті і налаштуйте алертинг.
Питання й відповіді (FAQ)
1) Якщо ping показує втрати, але TCP в порядку — це «реальна» втрата пакетів?
Може бути реальна ICMP-втрата, яка часто не має відношення до продуктивності додатку. Багато пристроїв обмежують ICMP по швидкості. Підтверджуйте TCP ретрансмітами і метриками додатку.
2) Який єдиний найкорисніший файл в Linux для «дропів під навантаженням»?
/proc/net/softnet_stat. Якщо стовпець dropped зростає під час інциденту — маєте дропи в беклозі ядра. Це зазвичай вказує на CPU/IRQ/швидкість пакетів.
3) Чому середні значення так погано вводять в оману при інтермітентних втратах?
Бо дропи часто трапляються в мікрошипах. Сплеск у 200 ms може переповнити чергу й спричинити видимі втрати, тоді як ваше середнє за 1 хвилину виглядає нормально.
4) Чи варто вимикати GRO/TSO/GSO, щоб tcpdump став «точним»?
Не як перший крок. Офлоади зменшують навантаження на CPU. Вимкнення їх може створити втрати через насичення softirq. Якщо треба тестувати — робіть це тимчасово, захопіть до/після і слідкуйте за softnet drops і CPU.
5) Як визначити, чи дропи на ingress чи egress?
Ingress: зростання RX misses/no-buffer, softnet drops або проблеми з receive сокетом. Egress: tc -s qdisc дропи, проблеми з TX чергами або shaping/policing. Захоплення по обидва боки межі робить це очевидним.
6) Чому невідповідність MTU виглядає «лише інколи»?
Бо не всі пакети великі. Малі запити проходять, великі відповіді чи аплоади зависають. Якщо PMTUD зламаний (часто через фільтровані ICMP), з’єднання може зависнути і ретрансмити до таймауту.
7) Чи може conntrack справді виглядати як втрата пакетів?
Так. Коли conntrack повний або сильно законтендований — нові потоки можуть падати. Клієнти бачать таймаути і повтори, і легко переплутати це з «зникненням пакетів».
8) Що, якщо tcpdump каже «packets dropped by kernel» під час захоплення?
Ваше захоплення не встигає, що часто буває на завантажених лінках. Звузьте фільтр, зменшіть snaplen, захоплюйте менше пакетів або з менш завантаженого місця. Не використовуйте втратне захоплення, щоб доводити мікрошипи.
9) Чи означає чисте ip -s link, що NIC в порядку?
Не обов’язково. Багато важливих лічильників є тільки в ethtool -S, а фізичні помилки можуть бути помітнішими на стороні свіча.
10) Як уникнути безконечних звинувачувальних суперечок між командами?
Узгодьте межі й докази: «пакет бачать тут, але не там», плюс лічильники, що зростають. Захоплення в двох точках перемагає думки щоразу.
Висновок: наступні кроки, що працюють
Інтермітентні втрати пакетів перестають бути містикою, коли ви припиняєте ставитись до них як до відчуття і починаєте думати про них як про переповнення черг або умовний провал шляху. Переможний хід — локалізувати межу втрат, використовуючи дельти лічильників і маленькі цільові захоплення.
Зробіть наступне, у порядку:
- На постраждалому хості зафіксуйте дельти для
netstat -s,ip -s link,ethtool -S,tc -s qdiscі/proc/net/softnet_statпротягом 1–5 хвилин. - Якщо дропи локальні — вирішіть, який домен їх володіє: NIC ring, softirq backlog, qdisc, conntrack або тиск на сокет.
- Якщо дропи не локальні — захопіть на обох кінцях (або по обидва боки межі) і робіть розмову про докази.
- Напишіть той ранбук, який вам потрібен сьогодні, поки біль ще свіжий. Тримайте його коротким. Вимагайте виводів у тікетах.
Найкращий план дебагу — той, який ви можете виконати втомленими, під тиском і з трьома людьми, що сперечаються у вухо. Побудуйте цей план, і інтермітентні втрати стануть звичайним вівторком.