Debian 13: TCP-перенадсилання вбивають продуктивність — знайдіть, де насправді втрати

Було корисно?

Це починається однаково щоразу: команда застосунка клянеться, що «мережа повільна», мережна команда клянеться, що «сервери скидaють пакети», а ви застрягаєте, дивлячись на панель, яка показує «TCP Retransmits», ніби це діагноз. Але це не діагноз. Це симптом.

На Debian 13 повторні відправлення можуть означати реальні втрати пакетів, колапс черг, проблеми з PMTU, дивну взаємодію офлоудів, перевантаження conntrack, перемішування пакетів або проміжний пристрій, який «допомагає» вашому трафіку. Завдання не в тому, щоб довести, що повторні відправлення є. Завдання — точно визначити, де саме відбувається втрата (або ілюзія втрати): на хості, гіпервізорі, NIC, комутаторі, брандмауері чи на стороні одержувача.

Що насправді означають повторні відправлення (і чого вони не означають)

TCP-перенадсилання відбуваються, коли відправник вважає, що сегмент не дійшов до одержувача. Важливе слово — «вважає». TCP робить висновки про втрату за відсутністю підтверджень (ACK), дубльованими ACK, блоками SACK і таймерами. Відсутність ACK може статися через:

  • Сегмент даних був відкинутий у дорозі.
  • ACK був відкинутий на зворотному шляху.
  • Сегмент прибув, але застряг за величезною чергою (bufferbloat), прийшов «занадто пізно» й викликав відновлення втрати.
  • Пакети були перемішані (reordering) і тимчасово «виглядали як втрачені».
  • Одержувач був настільки перевантажений, що не встиг надіслати ACK у часі.
  • Проміжний пристрій змінив MSS/MTU/ECN, спричинивши чорну діру або зупинку з’єднання.

Тож «високі retransmits» — це як сказати «пожежна сигналізація голосна». Так. Тепер треба знайти вогонь, підгорілий тост або людину, що курить під детектором.

У сучасному Linux стек TCP чудовий. Якщо ви бачите, що повторні відправлення «вбивають продуктивність», зазвичай система повідомляє, що щось під або поряд із TCP поводиться неправильно: кільця NIC, баги драйвера, взаємодії офлоудів, голодування IRQ або шляхи мережі, що кидають сплески.

Чиста істина: ваш застосунок може бути в порядку. Диски можуть бути в порядку. CPU може бути в порядку. Але повторні відправлення реальні, і вони гальмують вас. Виправте шлях.

Швидка методика діагностики

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

Спочатку: вирішіть, чи це один хост, один лінк або шлях

  1. Порівняйте кілька клієнтів/серверів. Якщо один хост Debian 13 — аутлайер, починайте з нього. Якщо всі хости бачать проблему з одним і тим же призначенням, підозрюйте шлях або одержувача.
  2. Перевірте лічильники інтерфейсу. Якщо NIC показує помилки RX/TX, drops, missed або «no buffer», швидше за все проблема на боці хоста.
  3. Перевірте TCP-статистику. Якщо retransmits зростають, а інтерфейсні дропи залишаються на місці, підозрюйте відчайдушне перевантаження шляху, перемішування, MTU-чорні діри або втрату ACK на звороті.

Далі: визначте напрям втрат (шлях даних vs шлях ACK)

  1. tcpdump на обох кінцях (або на одному кінці плюс span/mirror) і перевірте: чи відсутні сегменти даних на вході, чи відсутні ACK на виході?
  2. Перевірте асиметрію. Втрата на шляху ACK виглядає як «відправник перенадсилає, одержувач отримав дані».

Третє: протестуйте звичайних підозрюваних у найкоротшому контурі

  1. MTU/PMTUD (особливо VLAN, тунелі, jumbo frames, overlay-мережі).
  2. Офлоуди (GRO/LRO/TSO/GSO), коли захоплення пакетів виглядає «дивно» або коли відомо, що комбінація NIC/драйвер працює нестабільно.
  3. Голодування IRQ/softirq (високе навантаження CPU в ksoftirqd, дропи з «no buffer»).
  4. Брандмауер/conntrack (дропи, таймаути, «invalid» або тиск на таблицю conntrack).
  5. Bonding/LACP (перемішування пакетів між лінками, особливо з певними політиками хешування).

Одне правило: не налаштовуйте TCP, поки не доведете, що винен стек TCP. Більшість «налаштувань TCP» — дорога забобонна дія з гарною таблицею.

Факти й контекст для ситуаційних нарад

  • Логіка повторних відправлень TCP передує вашому дата-центру. Класичні алгоритми fast retransmit і fast recovery були формалізовані в 1990-х, коли Інтернет зростав і втрата стала нормою.
  • SACK (Selective Acknowledgment) змінив правила гри. Він дозволяє одержувачам точно сказати відправникам, які блоки дійшли, зменшуючи непотрібні перенадсилання на шляхах із втратою.
  • Linux довго має серйозну реалізацію TCP. Багато можливостей високопродуктивної мережі — як сучасні опції управління заторами — були випробувані в Linux до того, як стали «індустрійними стандартами».
  • CUBIC став стандартом у Linux, бо Інтернет прискорився. Поведінка на кшталт Reno виявилась надто консервативною для каналів з великою пропускною здатністю й великою затримкою.
  • RACK (Recent ACK) покращив виявлення втрат. Він намагається краще відрізняти перемішування від втрати, зменшуючи помилкові перенадсилання.
  • GRO/TSO офлоади змінили вигляд захоплень пакетів. tcpdump може показувати «гігантські» пакети або дивну сегментацію, бо NIC/ядро роблять роботу, яку раніше ви бачили «на дроті».
  • Ethernet не має вбудованої наскрізної надійності. Втрата пакетів дозволена при перевантаженні; TCP — шар надійності, а не комутатор.
  • Мікросплески — не новинка. Швидкі лінки і неглибокі буфери можуть скидати короткі сплески, навіть якщо середнє завантаження виглядає нормальним.
  • Помилки PMTUD повторюються класично. Фільтрація ICMP + тунелі/оверлеї = чорні діри, що виглядають як «випадкові повторні відправлення».

Одна перефразована думка від Werner Vogels: «Все ламається, постійно; проєктуйте й оперуйте так, ніби це так». (перефразована ідея)

Отримайте істину: виміряйте повторні відправлення, втрати та де вони відбуваються

«TCP retransmits» з’являється в моніторингу, бо корелює з поганим користувацьким досвідом. Але кореляція — не місце. Вам потрібні відповіді на три питання:

  1. Чи втрати реальні чи видимі? (Перемішування/запізнення пакетів можуть викликати відновлення без істинної втрати.)
  2. Чи відбувається це на хості? (Дропи драйвера/NIC/IRQ/черг.)
  3. Чи відбувається це в мережевому шляху? (Конгестія комутатора, MTU-чорна діра, дропи брандмауера.)

Debian 13 постачається з сучасним ядром і користувацьким простором. Це добра новина. Це також означає, що ви легко можете неправильно інтерпретувати інструменти, якщо не враховуєте офлоади, неймспейси, рівні віртуалізації та overlay-мережі. Ваш tcpdump — це не зізнання; це свідчення.

Жарт №1: Втрата пакетів схожа на офісну політику: рідко вона там, де найголосніша людина каже.

Практичні завдання: команди, виходи, рішення (12+)

Це польові завдання: виконуйте їх під час інциденту, і ви звузите простір пошуку, не починаючи тижневу «ініціативу з продуктивності мережі». Кожне завдання включає: команду, що означає типовий вихід, і яке рішення прийняти далі.

Завдання 1 — Підтвердити повторні відправлення та хто страждає (ss)

cr0x@server:~$ ss -ti dst 10.20.30.40
ESTAB 0 0 10.20.30.10:54322 10.20.30.40:443
	 cubic wscale:7,7 rto:204 rtt:5.2/0.8 ato:40 mss:1460 pmtu:1500 rcvmss:1460 advmss:1460 cwnd:10 bytes_acked:1453297 segs_out:12094 segs_in:11820 send 22.5Mbps lastsnd:12 lastrcv:12 lastack:12 pacing_rate 45.0Mbps unacked:3 retrans:57/1034 reordering:3

Значення: retrans:57/1034 показує перенадслані сегменти. Якщо повторні відправлення зростають під час падіння пропускної здатності, у вас проблема відновлення TCP, а не просто «повільний застосунок».

Рішення: Якщо повторні відправлення зосереджені на одному призначенні або інтерфейсі — звужуйте область пошуку. Якщо глобально — підозрюйте спільний елемент шляху (комутатор, брандмауер, гіпервізор, uplink).

Завдання 2 — Системні TCP-статистики (nstat / netstat)

cr0x@server:~$ nstat -az | egrep 'TcpRetransSegs|TcpTimeouts|TcpExtTCPSynRetrans|TcpExtTCPFastRetrans'
TcpRetransSegs                 18933              0.0
TcpTimeouts                    412                0.0
TcpExtTCPFastRetrans           12080              0.0
TcpExtTCPSynRetrans            55                 0.0

Значення: Зростання TcpTimeouts вказує на перенадсилання по RTO (гірше), а не на fast retransmit (часто через конгестію або перемішування). SYN-перенадсилання натякають на проблеми шляху/фільтрації.

Рішення: Якщо таймаути зростають — негайно перевіряйте MTU/чорні діри та серйозні дропи. Якщо в основному fast retransmits — зосередьтеся на конгестії, мікросплесках або перемішуванні.

Завдання 3 — Перевірити лічильники помилок і дропів NIC (ip -s link)

cr0x@server:~$ ip -s link show dev eno1
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq 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
    9876543210  8123456  0       1432     980     12034
    TX:  bytes  packets  errors  dropped  carrier collsns
    8765432109  7456123  0       0       0       0

Значення: Зростання dropped і missed у RX означає, що хост не встигав обробляти вхідні пакети (переповнення кільця, голодування IRQ, навантаження CPU).

Рішення: Якщо RX drops/missed зростають — пріоритезуйте сторону хоста: статистика драйвера, кільця, IRQ affinity, RPS/XPS, офлоади, конкуренція CPU.

Завдання 4 — Глибокі лічильники драйвера (ethtool -S)

cr0x@server:~$ sudo ethtool -S eno1 | egrep -i 'drop|miss|err|timeout|buffer|fifo' | head
     rx_dropped: 1432
     rx_missed_errors: 980
     rx_no_buffer_count: 975
     rx_fifo_errors: 0
     tx_timeout_count: 0

Значення: rx_no_buffer_count — це NIC, який каже: «у мене були кадри, але немає куди їх покласти». Це паличка-виручалочка для проблем з кільцями/IRQ/softirq.

Рішення: Збільшіть кільця (Завдання 9), розподіліть переривання, перевірте softirq-навантаження CPU (Завдання 6) і впевніться, що на цій машині не виконується важке firewall-оброблення.

Завдання 5 — Підтвердити швидкість лінка/дуплекс і авто-узгодження (ethtool)

cr0x@server:~$ sudo ethtool eno1 | egrep 'Speed|Duplex|Auto-negotiation|Link detected'
	Speed: 1000Mb/s
	Duplex: Full
	Auto-negotiation: on
	Link detected: yes

Значення: Сервер, що застряг на 1Gb/s, коли ви очікуєте 10/25/100Gb/s — це не «втрата TCP», це машина часу в 2009 рік.

Рішення: Виправте кабелі/SFP/конфігурацію комутатора. Не налаштовуйте TCP, щоб компенсувати понижене узгодження.

Завдання 6 — Перевірити навантаження softirq і конкуренцію CPU (mpstat / top)

cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.12.0 (server)  12/29/2025  _x86_64_  (32 CPU)

12:03:11 PM  CPU  %usr %nice %sys %iowait %irq %soft %steal %idle
12:03:12 PM  all  12.1  0.0   8.2   0.3    0.0  18.4   0.0   61.0
12:03:12 PM   7   5.0  0.0   6.1   0.0    0.0  72.3   0.0   16.6

Значення: Один CPU, завантажений у %soft, тоді як інші прості — це крик «дисбаланс переривань/softirq». Пакети приходять, але один ядро тоне.

Рішення: Перевірте розподіл IRQ (Завдання 7). Розгляньте ввімкнення/налаштування RPS/XPS або коригування IRQ affinity.

Завдання 7 — Перевірити розподіл IRQ для NIC (procfs)

cr0x@server:~$ grep -E 'eno1|eth0|ixgbe|i40e|mlx|ens' /proc/interrupts | head -n 5
  88:  12000342        0        0        0  IR-PCI-MSI 262144-edge  eno1-TxRx-0
  89:         3        0        0        0  IR-PCI-MSI 262145-edge  eno1-TxRx-1
  90:         1        0        0        0  IR-PCI-MSI 262146-edge  eno1-TxRx-2

Значення: Черга 0 обробляє практично всі переривання. Це створює RX-drops під навантаженням, що перетворюється на TCP-перенадсилання.

Рішення: Виправте affinity (irqbalance, ручні маски), перевірте, чи ввімкнено RSS, підтвердіть, що кілька черг активні.

Завдання 8 — Подивіться на дропи в qdisc (tc -s)

cr0x@server:~$ tc -s qdisc show dev eno1
qdisc mq 0: root
qdisc fq_codel 8001: parent :1 limit 10240p flows 1024 quantum 1514 target 5.0ms interval 100.0ms memory_limit 32Mb ecn
 Sent 8123456789 bytes 7456123 pkt (dropped 0, overlimits 0 requeues 2)
 backlog 0b 0p requeues 2

Значення: Якщо qdisc показує значні дропи, ви можете самі спричиняти втрати на egress (traffic shaping, неправильно підібраний fq_codel або занадто малий txqueuelen).

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

Завдання 9 — Перевірити й налаштувати розміри кілець NIC (ethtool -g / -G)

cr0x@server:~$ sudo ethtool -g eno1
Ring parameters for eno1:
Pre-set maximums:
RX:	4096
TX:	4096
Current hardware settings:
RX:	512
TX:	512

Значення: Маленьке RX-кільце може переповнюватися під час сплесків. Це дає RX-drops, які виглядають як «випадкові TCP-перенадсилання».

Рішення: Якщо ви бачите rx_no_buffer_count і missed drops, обережно збільшуйте RX/TX кільця і повторно тестуйте.

cr0x@server:~$ sudo ethtool -G eno1 rx 2048 tx 2048

Завдання 10 — Підтвердити MTU наскрізно і виявити невідповідності (ip link, ping -M do)

cr0x@server:~$ ip link show dev eno1 | head -n 1
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
cr0x@server:~$ ping -c 3 -M do -s 1472 10.20.30.40
PING 10.20.30.40 (10.20.30.40) 1472(1500) bytes of data.
1472 bytes from 10.20.30.40: icmp_seq=1 ttl=63 time=0.412 ms
1472 bytes from 10.20.30.40: icmp_seq=2 ttl=63 time=0.398 ms
1472 bytes from 10.20.30.40: icmp_seq=3 ttl=63 time=0.405 ms

--- 10.20.30.40 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2040ms

Значення: Це тест DF (don’t fragment). Якщо він не проходить на шляху, який ви вважаєте 1500/9000, ви знайшли проблему PMTU.

Рішення: Якщо DF-ping не проходить на очікуваних розмірах — зупиніться. Вирівняйте MTU або дозволіть ICMP «fragmentation needed». Перенадсилання — лише симптом.

Завдання 11 — Захоплення на хості та маркування повторних відправлень (tcpdump)

cr0x@server:~$ sudo tcpdump -i eno1 -nn 'host 10.20.30.40 and tcp port 443' -vv
tcpdump: listening on eno1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:05:01.101010 IP 10.20.30.10.54322 > 10.20.30.40.443: Flags [P.], seq 12001:13461, ack 8801, win 501, length 1460
12:05:01.104444 IP 10.20.30.10.54322 > 10.20.30.40.443: Flags [P.], seq 12001:13461, ack 8801, win 501, length 1460 (retransmission)
12:05:01.105000 IP 10.20.30.40.443 > 10.20.30.10.54322: Flags [.], ack 13461, win 8192, length 0

Значення: tcpdump позначить «(retransmission)» на основі того, що він бачить. Але пам’ятайте: точка захоплення має значення. Захоплення на відправнику не доводить, що пакет ніколи не покидав NIC.

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

Завдання 12 — Перевірити офлоади, коли захоплення виглядає неправильно (ethtool -k)

cr0x@server:~$ sudo ethtool -k eno1 | egrep 'tcp-segmentation-offload|generic-segmentation-offload|generic-receive-offload|large-receive-offload'
tcp-segmentation-offload: on
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off [fixed]

Значення: TSO/GSO/GRO можуть зробити захоплення оманливим і можуть погано взаємодіяти з певними драйверами або тунелями, особливо в віртуалізованих оверлеях.

Рішення: Якщо підозрюєте артефакти від офлоаду — тимчасово вимкніть їх на одному хості (не на всьому флоті) і виміряйте повторні відправлення знову.

cr0x@server:~$ sudo ethtool -K eno1 gro off gso off tso off

Завдання 13 — Перевірити навантаження conntrack і дропи nftables

cr0x@server:~$ sudo nft list ruleset | head -n 20
table inet filter {
	chain input {
		type filter hook input priority filter; policy drop;
		ct state established,related accept
		iif "lo" accept
		tcp dport { 22, 443 } accept
		counter packets 189234 bytes 120934234 drop
	}
}
cr0x@server:~$ sudo sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_count = 258901
net.netfilter.nf_conntrack_max = 262144

Значення: Якщо conntrack близький до максимуму, нові потоки можуть відкидатися або затримуватися. Це створює SYN-перенадсилання і «випадкові» застояні моменти.

Рішення: Якщо ви виконуєте stateful firewalling на завантаженому хості — або підвищіть ліміти з урахуванням пам’яті, або зменшіть відстежуваний трафік, або перемістіть фільтрацію поза хост.

Завдання 14 — Шукати перемішування і підказки DSACK (ss -i, nstat)

cr0x@server:~$ ss -ti src 10.20.30.10:54322
ESTAB 0 0 10.20.30.10:54322 10.20.30.40:443
	 cubic rtt:5.1/1.0 rto:204 mss:1460 cwnd:9 unacked:2 retrans:22/903 reordering:18
cr0x@server:~$ nstat -az | egrep 'TcpExtTCPDSACKRecv|TcpExtTCPDSACKOfoRecv|TcpExtTCPSACKReorder'
TcpExtTCPDSACKRecv             3812               0.0
TcpExtTCPDSACKOfoRecv          1775               0.0
TcpExtTCPSACKReorder           2209               0.0

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

Рішення: Досліджуйте LACP/bonding, ECMP-шляхи та будь-які пристрої, що роблять per-packet load balancing. Виправлення перемішування часто «вирішує перенадсилання» без зміни рівня втрат.

Завдання 15 — Підтвердити PMTU з точки зору ядра (ip route get)

cr0x@server:~$ ip route get 10.20.30.40
10.20.30.40 dev eno1 src 10.20.30.10 uid 1000
    cache mtu 1500

Значення: cache mtu у маршруті — це те, що ядро вважає безпечним. Якщо ви очікуєте 9000, а бачите 1500 — щось навчило менший PMTU.

Рішення: Якщо PMTU несподівано малий — перевірте тунелі/VPN/VXLAN/GRE і чи надходять ICMP «frag needed» і обробляються ними.

Завдання 16 — Перевірити стан bonding/LACP (якщо релевантно)

cr0x@server:~$ cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v6.12.0

Bonding Mode: IEEE 802.3ad Dynamic link aggregation
Transmit Hash Policy: layer3+4 (1)
MII Status: up
Slave Interface: eno1
MII Status: up
Slave Interface: eno2
MII Status: up

Значення: LACP сам по собі не гарантує послідовної доставки, якщо upstream неправильно налаштовано або якщо політика хешування змінюється. Деякі налаштування викликають перемішування пакетів під певними патернами потоків.

Рішення: Якщо лічильники перемішування зростають і у вас bonding — протестуйте з одним лінком або відрегулюйте політику хешування й конфігурацію port-channel upstream.

Моделі втрат, які вводять в оману розумних людей

1) «Немає дропів на інтерфейсі, але купа повторних відправлень»

Класичний застій у war room. Хост каже, що не відкидає. TCP каже, що перенадсилає. Обидва можуть бути праві.

  • Втрата на шляху: переповнення буферів комутатора, поліси/шейпінг upstream, погана оптика або брандмауер, що відкидає під навантаженням.
  • Втрата на шляху ACK: ваш відправник бачить відсутні ACK, перенадсилає, але одержувач дійсно отримав дані.
  • Затримки в чергах: пакети прибувають пізно (bufferbloat), викликаючи fast retransmit або таймаут, хоча їх не було втрачено.

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

2) Мікросплески: середнє завантаження обманює

Мікросплески — причина того, що «лінки на 20%» все одно скидають пакети. Сучасні системи можуть відправляти трафік сплесками: coalescing переривань, батчинг у ядрі, GRO, записи застосунків або реплікація зберігання, що штовхає великий шматок. Неглибокі буфери в ToR-комутаторах можуть скидати ці сплески за мікросекунди. Ваш SNMP-граф на 60-секундному інтервалі при цьому щасливо скаже «все нормально».

Що робити: попросіть телеметрію інтерфейсу комутатора про discards і buffer drop counters, бажано з високою роздільною здатністю. На хості дивіться rx no-buffer і softirq-навантаження. Якщо не можете отримати телеметрію комутатора, можна вивести мікросплески з «немає очевидних дропів на хості» плюс повторні відправлення під високим fan-in або синхронними відправниками.

3) PMTUD чорні діри: це не втрата, це мовчазне невідповідне MTU

Якщо ICMP «fragmentation needed» блокується або неправильно обробляється, великі пакети зникають. TCP перенадсилає. Згодом з’єднання зависає або повзає з дивною поведінкою MSS. Це особливо часто з тунелями, VPN і overlay-мережами.

Не гадати. Тестуйте з ping -M do. Якщо це не проходить на розумних розмірах — припиніть «налаштовувати TCP». Ви надсилаєте пакети, які шлях не може пронести.

4) Перемішування (reordering): пакети приходять, просто не пристойно

TCP передбачає, що перемішування менш імовірне, ніж втрата, хоча Linux став кращим у його розпізнаванні. Якщо ваша мережа робить per-packet load balancing (навіть навмисно), ви можете викликати перемішування. Неправильні налаштування bonding теж можуть це зробити.

Результат: дубльовані ACK, fast retransmits, DSACK. Пропускна здатність падає. Усі звинувачують «втрату пакетів», бо це графік, який у них є.

5) «Ми ввімкнули функцію X і стало гірше» (бо змінилось таймінг)

Офлоади, ECN, pacing, дисципліни черг — багато чого корисного. Але ввімкнення цих опцій у неправильному місці може змінити поведінку сплесків і таймінги настільки, що виставить слабке місце. Це не означає, що функція погана. Це означає, що середовище крихке.

Жарт №2: Вимкнути GRO, щоб «пофіксити мережу» — це як викинути пожежний датчик, щоб зменшити шум.

Три корпоративні міні-історії (що насправді йде не так)

Міні-історія 1: Інцидент, спричинений неправильним припущенням

Компанія розгортала новий флот Debian 13 за парою брандмауерів. Роллаут пройшов гладко, поки один сервіс — пакетний експорт — не почав таймаутити. Перенадсилання росли, RTO росли, а експорти стали «ненадійними». Власник застосунку наполягав, що це регресія в ядрі.

Мережна команда вказувала на чисті лічильники інтерфейсів на серверах. Ніяких RX-drops. Ніяких CRC-помилок. «Це не ми». SRE на виклику зробив найнуднішу річ: перевірив PMTU за допомогою ping -M do між хостами-експортерами і downstream API. Тест провалився на розмірах, які мали б працювати в тому VLAN.

Усі припускали, що VLAN — це простий 1500-байтовий Ethernet. Насправді ні. Посеред був сегмент тунелю, а брандмауери були налаштовані відкидати вхідні ICMP «fragmentation needed» як «непотрібний шум». PMTUD не працював, і шлях фактично чорнув більші пакети.

Виправлення не вимагало відкату Debian, нового драйвера NIC або танцю з sysctl. Дозволили потрібні типи ICMP і виставили MSS clamping на фаєрволі для тунеля. Перенадсилання впали, пропускна здатність повернулась, і ситуаційна нарада закінчилась до обіду.

Неправильне припущення було не «Debian 13 багатий». Неправильне припущення було «наша мережа має той MTU, про який ми думаємо». Ось як вас дзвонять посеред ночі.

Міні-історія 2: Оптимізація, що повернулась бумерангом

Інша організація хотіла витиснути більше пропускної здатності з реплікаційного трафіку. Хтось прочитав, що «більші буфери покращують продуктивність», тож під час вікна обслуговування збільшили розміри кілець NIC і змінили налаштування qdisc по всьому кластеру зберігання. Початкові тести виглядали добре: менше дропів, вищі пікові показники на синтетичних бенчмарках.

Потім з’явилась продукція. Чутливі до затримки сервіси, які ділили ті самі uplink-и, почали повідомляти таймаути. Перенадсилання росли скрізь, не лише у реплікації. Графіки не показували насичення лінка, тож звинувачення гепало між командами.

Проблема не в тому, що більші кільця «погані». Проблема в тому, що більші кільця плюс змінена поведінка qdisc збільшили чергування під сплесками. Хост став більше буферити, комутатор теж, і jitter RTT став достатньо великим, щоб RTO і відновлення втрат спрацьовували частіше. Це виглядало як втрата пакетів, але частина була затримкою доставки.

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

Ось чому не варто «оптимізувати» без моделі робочих навантажень. Швидко ≠ стабільно.

Міні-історія 3: Нудна, але правильна практика, що врятувала день

У третьої компанії один стій почав показувати підвищені TCP-перенадсилання на вузлах Debian 13 після апгрейду обладнання. Нічого не впало, просто стало досить повільно, щоб клієнти помітили. Перша думка — ганятися за версіями ядра, прошивками NIC і «можливо IPv6».

Але команда мала нудну практику: для кожного стійла існувала базова «золотая» знімка захоплення й лічильників, зроблена, коли стійло було перевірено як працездатне. Нічого особливого — просто ethtool -S, ip -s link, ss -s і короткий tcpdump. Це лежало в репозиторії поруч із нотатками про збірку стійла.

Порівняння поточних лічильників з базовими показало одну очевидну різницю: CRC та alignment-помилки на порту комутатора, що підключений до одного uplink-листа, були ненульовими і постійно зростали. На хостах помилок ще не було видно (комутатор бачив проблему шару фізики першим).

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

Нудні практики не роблять хороших доповідей на конференціях. Вони закінчують інциденти.

Типові помилки: симптом → корінь → виправлення

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

1) Високі TCP-перенадсилання, зростання RX-drops NIC

  • Симптом: Перенадсилання зростають з пропускною здатністю. ip -s link показує RX dropped/missed у збільшенні.
  • Ймовірна причина: Хост не встигає обслуговувати RX (IRQ прив’язаний, занадто малі кільця, баги драйвера, конкуренція CPU, великий nftables, оверхед віртуалізації).
  • Виправлення: Балансувати IRQ/RSS, збільшити кільця, перевірити RPS/XPS, зменшити навантаження firewall/conntrack, відсадити робочі навантаження від ядер, завантажених softirq, оновити прошивку/драйвер NIC за потреби.

2) Високі перенадсилання, немає дропів на хості, зростають SYN-перенадсилання

  • Симптом: TcpExtTCPSynRetrans зростає; з’єднання довго встановлюються.
  • Ймовірна причина: Брандмауер скидає пакети, таблиця conntrack повна, асиметрична маршрутизація через stateful-пристрій, або одержувач перевантажений/відмовляє.
  • Виправлення: Перевірте conntrack count/max, лічильники/логи брандмауера, забезпечте симетричну маршрутизацію, зменшіть відстежуваний трафік, підвищте потужність брандмауера або пропустіть відомий безпечний внутрішній трафік.

3) Повторні відправлення після ввімкнення jumbo frames

  • Симптом: Працює для малих відповідей, зависає на великих передачах; DF-pings не проходять.
  • Ймовірна причина: Розбіжність MTU десь (комутатор, брандмауер, overlay-тунель), PMTUD заблокований.
  • Виправлення: Узгодьте MTU наскрізно або обмежте MSS на краях; дозволіть ICMP frag-needed; перевіряйте DF-pings по реальному шляху.

4) Повторні відправлення з високими лічильниками «reordering»

  • Симптом: reordering в ss -i і зростання лічильників DSACK.
  • Ймовірна причина: ECMP/LACP хешування міняється, per-packet load balancing, лінки різної швидкості або неправильно налаштований bond/port-channel.
  • Виправлення: Забезпечте хешування по потоках, підтвердіть конфігурацію LACP, уникайте per-packet розподілу, протестуйте поведінку на одному лінку.

5) Перенадсилання «тільки під час бекапів» або «тільки в початку години»

  • Симптом: Періодичні сплески перенадсилань із запланованими джобами.
  • Ймовірна причина: Мікросплески й конгестія від синхронізованих відправників, тиск на буфери комутатора або колапс черг хоста.
  • Виправлення: Рознесіть розклади, застосуйте pacing/shaping для великих потоків, відокремте класи трафіку і попросіть/перевірте лічильники discard на комутаторі.

6) tcpdump показує перенадсилання, але логи одержувача кажуть, що дані прийшли

  • Симптом: Відправник перенадсилає; застосунок одержувача бачить дублікати або поза-порядком дані (або просто високий CPU).
  • Ймовірна причина: Втрата ACK на зворотному шляху або точка захоплення вводить в оману через офлоади/віртуальні комутатори.
  • Виправлення: Захопіть на обох кінцях; перевірте офлоади і точки захоплення; дослідіть зворотні пристрої і асиметричну маршрутизацію.

Чеклісти / план крок за кроком

Покроково: знайти, де втрати відбуваються за 60–90 хвилин

  1. Виберіть один уражений потік (джерело, призначення, порт). Не ганяйтеся за агрегованими графіками. Запустіть ss -ti dst <ip> і зафіксуйте retransmits, RTT, cwnd.
  2. Перевірте лічильники інтерфейсу хоста на обох кінцях: ip -s link, ethtool -S. Якщо RX drops/missed/no-buffer зростають на будь-якому боці — вирішуйте проблему на хості перед тим, як звинувачувати мережу.
  3. Перевірте баланс softirq на CPU: mpstat і /proc/interrupts. Якщо одне ядро завантажене — виправте IRQ/RSS.
  4. Підтвердіть MTU і PMTUD DF-pings на реальних розмірах. Якщо не проходить — виправте MTU/ICMP/MSS. Не рухайтесь далі, поки не пройде.
  5. Захопіть пакети під час піку перенадсилань. Якщо можливо — на обох кінцях у той самий проміжок. Підтвердьте, чи оригінальні сегменти з’являються в одержувача і чи повертаються ACK.
  6. Перевірте брандмауер/conntrack при потребі: лічильники nft, conntrack count/max, логи. Якщо таблиці майже повні або лічильники інкрементуються — виправте цей шар.
  7. Досліджуйте перемішування, якщо лічильники ростуть: bonding, ECMP, overlay. Спробуйте контрольований тест, обходячи bond або зафіксувавши один шлях.
  8. Залучіть мережну команду з конкретикою: «дропи на порту комутатора X», «CRC-помилки на uplink», «PMTU падає при 1472», «сплески reordering коли bond активний». Розмите «retransmits are high» дає розмиті відповіді.

Операційний чекліст: щоб не переживати це знову

  • Базові знімки ethtool -S, ip -s link, ss -s для відомо нормальних хостів.
  • Логування помилок/discard на портах комутаторів і кореляція з вікнами інцидентів.
  • Стандартизувати MTU по домену; документувати місця змін (тунелі, оверлеї, WAN).
  • Віддавати перевагу per-flow hashing; уникати per-packet load balancing для TCP-важких навантажень.
  • Розумно підбирати розміри conntrack; не дозволяйте дефолтам керувати критичними фаєрволами самостійно.
  • Вимагати «мапу точок захоплення» у віртуалізованих середовищах (host, VM, vSwitch, фізичний).

Питання й відповіді

1) Чи завжди TCP-перенадсилання означають втрату пакетів?

Ні. Це реакція відправника на відсутні ACK. Істинна втрата часта, але перемішування і надмірне чергування теж поширені.

2) Чому перенадсилання так сильно руйнують пропускну здатність?

TCP зменшує congestion window, коли вважає, що сталася втрата. Це обмежує швидкість відправлення. На шляхах з високим BDP відновлення може бути повільним.

3) Якщо лічильники NIC не показують дропів, чи може хост усе одно бути винен?

Так. Дропи можуть відбуватися в місцях, які ви не перевіряєте: рівні віртуального комутатора, firewall-хуки, conntrack або upstream. Також не всі драйвери коректно видають усі лічильники дропів.

4) tcpdump каже «retransmission». Це остаточно?

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

5) Чи слід вимикати GRO/GSO/TSO, щоб виправити перенадсилання?

Тільки як діагностику на одному хості. Якщо це допомагає, ви дізналися про взаємодію драйвера/офлоаду, але це не доводить правильну постійну конфігурацію.

6) Як визначити, чи це проблема MTU/PMTUD?

DF-ping, що не проходить на очікуваних розмірах, — сильний сигнал. Також звертайте увагу на зависання великих передач і дивну поведінку MSS. Виправляйте оброблення ICMP frag-needed і узгодженість MTU.

7) Чому перенадсилання стрибають під час бекапів або реплікації?

Потоки великого обсягу викликають сплески і конгестію. Можна отримати мікросплески, навіть коли середнє завантаження помірне. Розгляньте pacing, рознесення розкладів або розділення трафіку.

8) Чи може conntrack спричиняти перенадсилання навіть якщо сервер «не фаєрвол»?

Так. Якщо nftables відстежує трафік за замовчуванням (поширено), таблиця conntrack може заповнитися або стати дорогим по CPU, спричиняючи дропи й затримки — особливо при сильній хвилі підключень.

9) Який найшвидший доказ, що шлях мережі втрачає пакети?

Одночасні захоплення на відправнику й одержувачі, що показують відсутні сегменти на прийманні при чистих лічильниках хостів, сильно вказують на дропи шляху. Лічильники discard на комутаторі ставлять крапку.

10) Чи слід спочатку налаштовувати sysctl, як-от tcp_rmem/tcp_wmem?

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

Наступні кроки, які можна зробити сьогодні

Припиніть сприймати «TCP retransmits» як корінну причину. Сприймайте це як слід.

  1. Виберіть один уражений потік і захопіть ss -ti вихід під час проблеми.
  2. Перевірте ip -s link і ethtool -S на обох кінцях на предмет drops, missed, no-buffer, CRC.
  3. Підтвердіть MTU за допомогою DF-pings по реальному шляху.
  4. Перевірте баланс softirq і розподіл IRQ.
  5. Якщо ще неясно — захопіть пакети на обох кінцях і порівняйте, що вийшло з відправника і що прийшло.
  6. Тільки потім коригуйте кільця/офлоади/qdisc — і робіть це вибірково, з можливістю відкату.

Якщо ви робите це методично, суперечка про «чиє це» стає нудною. Нудно — це добре. Нудно означає, що ви майже виправили проблему.

← Попередня
RAIDZ2 в ZFS: баланс ємності та виживання (зазвичай)
Наступна →
ZFS Proxmox: значення зберігання ВМ, які варто змінити негайно

Залишити коментар