Ubuntu 24.04: коли GRO/LRO/TSO оффлоуди ламають систему — як протестувати і безпечно відключити

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

Ви оновилися до Ubuntu 24.04, мережева карта виглядає здоровою, CPU байдуже, а додаток задихається: дивні стрибки затримки, ненадійні з’єднання, захоплення пакетів, які брешуть, або реплікація зберігання, що раптово «потребує більше пропускної здатності», хоча використовує менше. Хтось каже «вимкніть оффлоуди». Хтось інший каже «ніколи не чіпайте оффлоуди». Обидва напівправі — а це найнебезпечніший вид правоти.

Це польовий путівник, який допоможе довести, коли GRO/LRO/TSO (та їхні сусіди) є причиною, як їх відключити без ускладнень і як зробити це так, щоб о третій ночі ви могли відкотитися з гідністю.

Що саме роблять GRO/LRO/TSO (і чому вони ламають систему)

Мережеві оффлоуди — це вигідна угода: перенесення роботи з кожним пакетом з CPU на NIC дає вищу пропускну здатність і менше навантаження на процесор. Рахунок приходить тоді, коли «пакет», який бачить ОС, — не те, що перетинає дріт, або коли якийсь проміжний шар очікує нормальних сегментів, а насправді бачить злитого монстра.

GRO: Generic Receive Offload

GRO — це програмна функція Linux, яка об’єднує кілька вхідних пакетів в один більший «супер-пакет» перед передачею в стек. Це зменшує обробку на пакет і кількість переривань. Чудово для пропускної здатності. Погано, коли потрібне точне відстеження кожного пакета, коли інструменти для захоплення очікують реальності, або коли бага в драйвері/кернелі неправильно обробляє межі сегментації.

GRO — це не властивість дроту. Це локальна оптимізація. На дроті все ще проходять звичайні кадри MTU. Ваш хост може показувати менше, але більші пакети в захопленнях і лічильниках, бо стек їх злив.

LRO: Large Receive Offload

LRO зазвичай реалізується на NIC/драйвері і теж виконує коалесценцію прийому. Воно може бути навіть агресивнішим за GRO. Також воно створює більше проблем при маршрутизації, тунелюванні, VLAN та у всьому, що очікує суворих меж пакетів. Багато середовищ просто тримають LRO вимкненим, особливо в віртуалізованих або з великою кількістю оверлеїв мережах.

TSO/GSO: сегментація при передачі (апаратна або програмна)

TSO (TCP Segmentation Offload) дозволяє кернелю передати великий TCP-пейлод NIC, а NIC розіб’є його на сегменти розміру MSS і порахує контрольні суми. GSO (Generic Segmentation Offload) — це програмний еквівалент для протоколів, які NIC не «розуміє». Зазвичай це безпечно і корисно — поки не стає небезпечним: баги драйвера, проблеми з контрольними сумами, дивні взаємодії з тунелями або обладнанням у шляху, яке поводиться некоректно при певних викидах/сегментних патернах.

Checksum offloads: прихований порушник

Rx/Tx checksum offload означає, що контрольні суми можуть бути пораховані/перевірені апаратурою NIC. Захоплення пакетів на хості можуть показувати «погану контрольну суму», бо контрольна сума ще не була заповнена в момент захоплення. Це не обов’язково означає, що мережа зіпсована; це помилкова гіпотеза.

Одна перефразована ідея від John Allspaw (операції/надійність): «Інциденти трапляються, коли реальність відходить від нашої ментальної моделі». Оффлоуди — це механізм, що виробляє таку розбіжність.

Жарт №1: Оффлоуди — як найняти інтернів для паперів — швидко й дешево, поки вони не «оптимізують» вашу систему зберігання у сучасне мистецтво.

Факти та історія: чому це повторюється

  • Факт 1: LRO з’явився раніше за GRO і широко вимикався в сценаріях маршрутизації/тунелювання, бо може зливати пакети так, що порушує припущення пересилання.
  • Факт 2: GRO було введено як безпечніша, стек-усвідомлена альтернатива LRO, але воно все одно змінює видимість пакетів для інструментів на кшталт tcpdump та споживачів AF_PACKET.
  • Факт 3: TSO став мейнстрімом, коли 1 Gbit/s перетворився на 10/25/40/100+ Gbit/s; CPU не витримують обробку кожного пакета на сучасних швидкостях лінії.
  • Факт 4: «Погана контрольна сума» в tcpdump на хості часто є артефактом захоплення з checksum offload, а не реальним провалом на дроті.
  • Факт 5: Багато CNIs та стеків оверлеїв (VXLAN/Geneve) мали періоди, коли комбінації оффлоудів були багованими, поки драйвери й ядра не дозріли.
  • Факт 6: RSS (Receive Side Scaling) і RPS/XPS були розроблені, бо однопотокова обробка прийому стала вузьким місцем значно раніше за пропускну здатність NIC.
  • Факт 7: Модерація переривань/злиття переривань може призводити до стрибків затримки при малому трафіку, навіть якщо вона покращує пропускну здатність під високим навантаженням.
  • Факт 8: Віртуалізація додала ще один рівень: virtio-net і vhost можуть робити власні батчінги/коалесценцію, посилюючи ефекти оффлоудів.
  • Факт 9: Точність захоплення пакетів завжди була «максимально можлива», коли додаєш оффлоуди; захоплення на SPAN/TAP або на маршрутизаторі часто показує іншу картину, ніж на кінцевій точці.

Швидкий план діагностики (перший/другий/третій)

Перший: вирішіть, чи ви дебагуєте коректність чи продуктивність

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

Другий: знайдіть горлову точку за один прохід

  1. Шукайте ретрансміси, дропи та скидання. Якщо TCP-регенерації стрімко зростають при низькій завантаженості лінку, ви маєте втрати або перестановку (реальні чи видимі).
  2. Перевірте завантаження CPU по softirq. Якщо ksoftirqd або один ядро зависає на максимумі, ви прив’язані по швидкості пакетів або має місце неправильне спрямування (RSS/IRQ affinity).
  3. Порівняйте лічильники хоста й комутатора. Якщо хост пише «drops», а порт комутатора чистий, проблема ймовірно в стеку/драйвері/оффлоуді хоста.

Третій: виконайте два контрольованих A/B тести

  1. A/B оффлоуди: вмикайте/вимикайте GRO/LRO/TSO в локалізований спосіб, вимірюйте затримку/ретрансміси/пропускну здатність.
  2. A/B MTU і шлях: тестуйте стандартний MTU проти jumbo, і пряме host-to-host проти проходження через оверлей/VPN.

Ваша мета — не «зробити числа більшими». Ваша мета: довести причинно-наслідковий зв’язок, а потім застосувати найменше рішення, яке усуває режим відмови.

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

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

Завдання 1: Визначте реальний інтерфейс і драйвер

cr0x@server:~$ ip -br link
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
enp5s0f0         UP             3c:fd:fe:aa:bb:cc <BROADCAST,MULTICAST,UP,LOWER_UP>
enp5s0f1         DOWN           3c:fd:fe:aa:bb:cd <BROADCAST,MULTICAST>

Значення: Виберіть інтерфейс, який несе трафік (тут: enp5s0f0). «UP, LOWER_UP» означає, що лінк піднятий.

Рішення: Чіпайте оффлоуди лише на активному інтерфейсі. Не робіть масових змін на всіх NIC, якщо вам подобаються ігри в здогадки.

cr0x@server:~$ sudo ethtool -i enp5s0f0
driver: ixgbe
version: 6.8.0-41-generic
firmware-version: 0x800003e7
bus-info: 0000:05:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no

Значення: Драйвер і прошивка мають значення. «Працювало на 22.04» — не доказ; це спогад.

Рішення: Якщо проблеми почалися після зміни ядра/прошивки, тримайте це у списку гіпотез.

Завдання 2: Інвентаризація поточних налаштувань оффлоудів (базова)

cr0x@server:~$ sudo ethtool -k enp5s0f0
Features for enp5s0f0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on

Значення: Це ваша відправна точка. Зверніть увагу, що вже вимкнено (часто LRO).

Рішення: Скопіюйте це в нотатки інциденту. Коли ви відкотитесь, відкотіться до фактів, а не до відчуттів.

Завдання 3: Перевірте, чи бачите ви ретрансміси (часто перша підказка «оффлоуд зламав»)

cr0x@server:~$ nstat -az | egrep 'Tcp(RetransSegs|ExtTCPSynRetrans|OutRsts|InErrs)'
TcpRetransSegs                1842               0.0
TcpExtTCPSynRetrans           17                 0.0
TcpOutRsts                    92                 0.0
IpInErrs                      0                  0.0

Значення: Зростання TcpRetransSegs під час навантаження вказує на втрати, перестановку або дивні властивості шляху.

Рішення: Якщо ретрансміси ростуть, а CPU та лінк виглядають нормально, підозрюйте взаємодію драйвера/оффлоудів/тунелю перш ніж звинувачувати «мережу».

Завдання 4: Доведіть, чи дропи на NIC, у стеку чи десь ще

cr0x@server:~$ ip -s link show enp5s0f0
2: enp5s0f0: <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  9123456      0   18421       0    1234
    TX:  bytes packets errors dropped carrier collsns
    8765432109  8234567      0       0       0       0

Значення: RX drops тут видимі на хості. Це можуть бути переповнення кілець, відставання CPU або поведінка драйвера.

Рішення: Якщо RX drops ростуть під навантаженням, слід перевірити розміри кілець, розподіл IRQ і GRO/LRO перед тим, як підлаштовувати таймаути додатку.

Завдання 5: Перевірте, чи softirq справді є вузьким місцем

cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.8.0-41-generic (server)  12/30/2025  _x86_64_  (32 CPU)

12:00:01 AM  CPU   %usr %nice  %sys %iowait %irq %soft  %steal %guest %gnice  %idle
12:00:02 AM  all    4.2  0.0   6.1    0.1   0.3  7.8     0.0    0.0    0.0   81.5
12:00:02 AM    7    2.1  0.0   4.9    0.0   0.2  48.7    0.0    0.0    0.0   44.1

Значення: Одне ядро з дуже високим %soft вказує на концентрацію обробки прийому на одній черзі/IRQ.

Рішення: Перед тим як вимикати оффлоуди «бо інтернет», перевірте RSS/IRQ affinity. Оффлоуди — не єдиний важіль.

Завдання 6: Перевірте розподіл переривань і чи не захоплює одну чергу

cr0x@server:~$ awk '/enp5s0f0/ {print}' /proc/interrupts | head
  74:  1283921   2031   1888   1999   2101   1902   1988   2010   PCI-MSI 524288-edge      enp5s0f0-TxRx-0
  75:     1932 1290033   1890   2011   1998   1887   2002   2017   PCI-MSI 524289-edge      enp5s0f0-TxRx-1

Значення: Це виглядає більш-менш збалансовано. Якщо ви бачите один лічильник IRQ, що домінує, RSS або affinity неправильно налаштовані.

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

Завдання 7: Перевірте розміри кілець (дропи можуть бути через брак буферів)

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

Значення: Поточні кільця менші за максимум.

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

Завдання 8: Підтвердьте швидкість/дуплекс і виявляйте дивну автоузгодження

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

Значення: Очевидно, але ви будете здивовані, як часто «мережева бага» — це відкат до 1G.

Рішення: Якщо швидкість неправильна, зупиніться. Виправте лінк/оптику/кабель/порт комутатора перед тим, як ганятися за оффлоудами.

Завдання 9: Використовуйте tcpdump правильно, коли задіяні оффлоуди

cr0x@server:~$ sudo tcpdump -i enp5s0f0 -nn -s 96 tcp and port 443 -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp5s0f0, link-type EN10MB (Ethernet), snapshot length 96 bytes
12:00:10.123456 IP 10.0.0.10.51532 > 10.0.0.20.443: Flags [S], seq 123456789, win 64240, options [mss 1460,sackOK,TS val 111 ecr 0,nop,wscale 7], length 0
12:00:10.123789 IP 10.0.0.20.443 > 10.0.0.10.51532: Flags [S.], seq 987654321, ack 123456790, win 65160, options [mss 1460,sackOK,TS val 222 ecr 111,nop,wscale 7], length 0

Значення: tcpdump на кінцевій точці все ще корисний для рукопотискання й таймінгів. Але сегментація payload і контрольні суми можуть вводити в оману.

Рішення: Якщо ви діагностуєте втрати пакетів або проблеми з MTU, подумайте про захоплення на SPAN/TAP комутатора або тимчасове вимкнення GRO для вікна захоплення.

Завдання 10: Перевірте проблеми шляху MTU (оффлоуди інколи маскують/запускають їх)

cr0x@server:~$ ping -c 3 -M do -s 8972 10.0.0.20
PING 10.0.0.20 (10.0.0.20) 8972(9000) 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.0.0.20 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2049ms

Значення: Ваш інтерфейс має MTU 1500, тому jumbo ping не проходить локально. Це нормально, якщо ви очікуєте 1500.

Рішення: Не змішуйте очікування jumbo з очікуваннями TSO/GSO. Якщо вам потрібні jumbo, налаштуйте їх повсюди, а потім повторіть тест оффлоудів.

Завдання 11: Виміряйте пропускну здатність і CPU за допомогою iperf3 (базовий вимір перед зміною оффлоудів)

cr0x@server:~$ iperf3 -c 10.0.0.20 -P 4 -t 10
Connecting to host 10.0.0.20, port 5201
[SUM]   0.00-10.00  sec  10.9 GBytes  9.35 Gbits/sec  0             sender
[SUM]   0.00-10.00  sec  10.8 GBytes  9.29 Gbits/sec                  receiver

Значення: Хороша відправна точка. Якщо оффлоуди зламані, ви часто бачите падіння пропускної здатності з ретрансмісами або шалене завантаження CPU.

Рішення: Запишіть це. Будь-яка зміна має або перевершити цей результат, або виправити коректність без неприйнятної деградації.

Завдання 12: Тимчасово вимкніть GRO і подивіться, чи перемістяться симптоми

cr0x@server:~$ sudo ethtool -K enp5s0f0 gro off
cr0x@server:~$ sudo ethtool -k enp5s0f0 | egrep 'generic-receive-offload|large-receive-offload'
generic-receive-offload: off
large-receive-offload: off

Значення: GRO тепер вимкнено. LRO залишається вимкненим.

Рішення: Повторіть тест навантаження і спостерігайте ретрансміси/затримку. Якщо коректність покращується миттєво, GRO був принаймні частиною режиму відмови.

Завдання 13: Вимкніть TSO/GSO (обережно: може підвищити CPU/швидкість пакетів)

cr0x@server:~$ sudo ethtool -K enp5s0f0 tso off gso off
cr0x@server:~$ sudo ethtool -k enp5s0f0 | egrep 'tcp-segmentation-offload|generic-segmentation-offload'
tcp-segmentation-offload: off
generic-segmentation-offload: off

Значення: Сегментація при передачі тепер відбуватиметься меншими шматками або повністю програмно, залежно від стеку і NIC.

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

Завдання 14: Перевірте статистику на рівні драйвера на наявність тривожних ознак (дропи, пропуски, помилки)

cr0x@server:~$ sudo ethtool -S enp5s0f0 | egrep -i 'drop|dropped|miss|error|timeout' | head -n 20
rx_missed_errors: 0
rx_no_buffer_count: 124
rx_errors: 0
tx_timeout_count: 0

Значення: rx_no_buffer_count вказує на голодування прийомних буферів; це часто розміри кілець, CPU або поведінка під сплесками.

Рішення: Збільшіть кільця, налаштуйте модерацію IRQ або зменшіть сплески перед тим, як постійно вимикати оффлоуди по всьому флоту.

Завдання 15: Подивіться на qdisc і черги (стрибки затримки можуть бути локальними)

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

Значення: Статистика дисципліни черг показує дропи/переперендери. Не весь біль на дроті.

Рішення: Якщо бачите локальні qdisc-дропи, вимкнення GRO вам не допоможе; маєте проблеми з чергуванням/буферизацією або shaping.

Завдання 16: Перевірте conntrack або шлях фаєрволу (часто звинувачують оффлоуди)

cr0x@server:~$ sudo conntrack -S | egrep 'insert_failed|drop|invalid'
insert_failed=0
drop=0
invalid=0

Значення: Conntrack не плавиться. Гарно.

Рішення: Якщо лічильники conntrack drop/insert_failed ростуть, у вас проблема з таблицею станів; не «виправляйте» це вимиканням GRO.

Як безпечно відключити оффлоуди (тимчасово, постійно, локально)

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

Тимчасові зміни (тільки runtime)

Використовуйте ethtool -K для миттєвого A/B тесту. Це не переживає перезавантаження. Це — перевага при експериментах.

cr0x@server:~$ sudo ethtool -K enp5s0f0 gro off lro off tso off gso off rx off tx off
Cannot change rx-checksumming
Cannot change tx-checksumming

Значення: Деякі функції не можна перемкнути на певних драйверах/NIC. Це нормально.

Рішення: Не боріться з апаратурою. Перемикайте те, що можете, і коригуйте план тестування. Часто саме GRO/TSO дають найбільший ефект.

Постійні зміни через systemd-networkd (природний для Ubuntu 24.04 шлях)

На Ubuntu 24.04 багато серверів працюють із systemd-networkd під капотом, навіть якщо ви використовуєте netplan для опису конфігурації. Сенс: ви хочете, щоб оффлоуди встановлювалися під час підняття лінку, а не скриптом, який «хтось» забув встановити на половині флоту.

Створіть .link файл, щоб відповідати інтерфейсу по імені або MAC і застосувати налаштування оффлоудів. Приклад по імені:

cr0x@server:~$ sudo tee /etc/systemd/network/10-enp5s0f0.link >/dev/null <<'EOF'
[Match]
OriginalName=enp5s0f0

[Link]
GenericReceiveOffload=false
TCPSegmentationOffload=false
GenericSegmentationOffload=false
LargeReceiveOffload=false
EOF
cr0x@server:~$ sudo systemctl restart systemd-networkd
cr0x@server:~$ sudo ethtool -k enp5s0f0 | egrep 'generic-receive-offload|tcp-segmentation-offload|generic-segmentation-offload|large-receive-offload'
tcp-segmentation-offload: off
generic-segmentation-offload: off
generic-receive-offload: off
large-receive-offload: off

Значення: Оффлоуди застосовуються після рестарту/ренеготації лінку.

Рішення: Якщо постійна конфігурація застосовується коректно і виправляє проблему без неприйнятного навантаження CPU, ви можете розгортати поступово.

Постійні зміни через oneshot unit systemd (працює скрізь, менш елегантно)

Якщо ви не можете покладатися на налаштування link systemd-networkd (змішане середовище, кастомні імена NIC або ви просто хочете щось грубе), використайте systemd oneshot, що запускається після підняття мережі.

cr0x@server:~$ sudo tee /etc/systemd/system/ethtool-offloads@.service >/dev/null <<'EOF'
[Unit]
Description=Set NIC offloads for %I
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/sbin/ethtool -K %I gro off lro off tso off gso off
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF
cr0x@server:~$ sudo systemctl enable --now ethtool-offloads@enp5s0f0.service
Created symlink /etc/systemd/system/multi-user.target.wants/ethtool-offloads@enp5s0f0.service → /etc/systemd/system/ethtool-offloads@.service.

Значення: Оффлоуди встановлюються під час завантаження для цього інтерфейсу.

Рішення: Використовуйте це, коли потрібна передбачувана поведінка швидко. Потім замініть на чистіший link-рівень конфігурації.

Локалізація: вимикайте лише те, що потрібно

На практиці:

  • Якщо захоплення пакетів вводить в оману або користувацький процес, що споживає пакети, плутається: тимчасово вимикайте GRO (іноді й checksum offload) для діагностики.
  • Якщо тунелі/овералеї поводяться дивно: спробуйте спочатку вимкнути TSO/GSO, потім GRO.
  • Якщо ви маршрутизуєте/містите: тримайте LRO вимкненим. Більшість production-середовищ ніколи його не вмикають.

Перевірте, чи ви не «виправили» проблему за рахунок голоду CPU

Після вимкнення оффлоудів повторіть навантаження і слідкуйте за:

  • CPU %soft (завантаження softirq)
  • RX drops і rx_no_buffer_count
  • p99 затримка і ретрансміси

Жарт №2: Найшвидший спосіб довести, що оффлоуди «вирішили» проблему — створити нову точку вузького місця CPU — природа не любить вакууму, як і Linux-мережі.

Три міні-історії з корпоративного світу (анонімізовані, правдоподібні, технічно коректні)

1) Інцидент, викликаний неправильною гіпотезою: «Погані контрольні суми означають, що мережа шкідливить пакети»

Команда платежів помітила періодичні TLS-помилки після перенесення сервісу на нові хости з Ubuntu 24.04. Захоплення пакетів на клієнтському хості показувало низку попереджень «bad checksum». Очікувана висновок був передбачуваний: мережеве обладнання деформує пакети. Мережеву команду викликали, відкрита war room, і всі почали шукати привидів.

Перше припущення було помилкою: що попередження контрольної суми в захопленні на хості — доказ корупції на дроті. На сучасному Linux з увімкненим TX checksum offload tcpdump може захопити пакети до того, як NIC заповнить контрольну суму. Пакет на дроті в порядку; пакет у вашому захопленні неповний у цій точці.

Друга помилка була в ескалації по скріншоту. Старший інженер нарешті попросив дві речі: захоплення з SPAN-порту комутатора і вивід ethtool -k. SPAN-пакет показав дійсні контрольні суми. Захоплення на кінцевій точці виглядало «погано» лише при увімкнених оффлоудах.

Реальна проблема виявилася не пов’язаною з контрольними сумами: неправильно розмічена таблиця conntrack на спільному шлюзі скидала з’єднання під сплесками. Оффлоуди були невинними; інструменти захоплення вводили в оману.

Що змінило прийняття рішень: вони оновили runbook чергування, щоб трактувати «bad checksum» як артефакт діагностики, поки це не підтверджено поза хостом. Також стандартизували метод «захоплення з оффлоудами вимкненими на 2 хвилини», коли потрібні захоплення з кінцевої точки.

2) Оптимізація, що відпрацювала проти: «Увімкнути всі оффлоуди для максимуму продуктивності»

Платформна група, що запускала контейнери, мала завдання підвищити щільність вузлів. Хтось помітив, що на деяких вузлах LRO вимкнено і вирішив «уніфікувати» флот для пропускної здатності. Вони запхали зміну в продакшн, вмикнувши все, що рекламувало NIC. Бенчмарки пропускної здатності в синтетичних тестах виглядали чудово. Зміна пішла в продакшн.

Через два дні до служби підтримки почали приходити дивні скарги: gRPC-потоки зависали, спорадичні таймаути між подами і патерн, де відмови частіше на вузлах із великим east-west трафіком. CPU був у нормі. Мережа — у нормі. Логи не допомагали. Інцидент мав той огидний запах: все нормальне, крім досвіду користувача.

Причиною виявився LRO, що погано взаємодіяв з інкапсульованим трафіком і тим, як деякі компоненти спостерігають межі пакетів. Система не «кидала пакети», скоріше створювала дивну агрегацію, яка виявляла граничні баги в оверлей-пасі. Вимкнення LRO виправило це миттєво.

Урок від backfire простий: оффлоуди — не «безкоштовні прапори продуктивності». Це зміни в поведінці. Якщо ваше середовище використовує оверлеї, middlebox-и або складні datapath-и, ставтеся до оффлоудів як до оновлення ядра: тестуйте їх на репрезентативному трафіку, а не лише iperf.

Вони відкотилися до консервативної бази: LRO вимкнено всюди, TSO/GSO увімкнені, поки не доведено їх шкідливість, і дозволили GRO там, де воно не заважає спостережуваності або пакетній обробці.

3) Нудна, але правильна практика, що врятувала день: «A/B тест на одному хості з таймером відкату»

Команда зберігання, що запускала реплікацію трафіку по 25G лініях, почала помічати стрибки відставання реплікації після оновлення ОС. Явних втрат пакетів не було, але відставання реальне й корелювало з піками навантаження. Перший імпульс був налаштувати додаток і додати пропускну здатність. Вони втрималися.

Їхній SRE-лідер наполіг на експерименті з одним вузлом: оберіть одного відправника і одного отримувача, ізолюйте шлях і перемикайте оффлоуди в контрольованій матриці (тільки GRO, тільки TSO, обидва). Кожна зміна мала заздалегідь записану команду відкату, і вони використовували таймер, щоб повернути налаштування за 20 хвилин, якщо не скасувати. Нудно. Правильно.

Експеримент дав дієвий результат: вимкнення TSO/GSO прибирало стрибки відставання, але значно підвищувало CPU. Вимкнення GRO майже не впливало. Це звузило підозри до взаємодії сегментації передачі, а не коалесценції прийому.

З цим доказом вони оновили прошивку NIC на ураженій моделі і повторно протестували. Після оновлення TSO/GSO можна було залишити увімкненими. Вони уникли постійного навантаження CPU і не переробляли топологію зберігання.

Практика, що врятувала день, була не в якомусь хитрому sysctl. Це дисципліна: одна зміна, один хост, один вимірюваний результат і гарантований відкат.

Поширені помилки: симптом → корінна причина → виправлення

1) Симптом: tcpdump показує «bad checksum» у вихідних пакетах

Корінна причина: TX checksum offload; tcpdump захопив пакет до того, як checksum була порахована.

Виправлення: Захопіть на SPAN/TAP або тимчасово вимкніть TX checksum offload для захоплення (ethtool -K IFACE tx off) і перевірте знову.

2) Симптом: p99 затримки стрибають при малому трафіку, пропускна здатність у порядку при великому

Корінна причина: Модерація/коалесценція переривань налаштована під пропускну здатність; CPU прокидається рідше, додаючи затримку.

Виправлення: Налаштуйте модерацію переривань NIC (ethtool -c/-C), і тільки потім розглядайте зміни GRO.

3) Симптом: Kubernetes мережа між подами нестабільна після оновлення

Корінна причина: Взаємодія оффлоудів і оверлею/тунелю (TSO/GSO/GRO з VXLAN/Geneve), іноді специфічна для драйвера.

Виправлення: A/B вимкніть TSO/GSO спочатку на уражених вузлах; тримайте LRO вимкненим. Підтвердіть ретрансмісами й тестами навантаження.

4) Симптом: RX drops ростуть на хості під сплесками, комутатор показує чисті лічильники

Корінна причина: Голод прийомного буфера/кільця або backlog softirq хоста; не обов’язково зовнішні втрати.

Виправлення: Збільшіть розмір RX кілець (ethtool -G), підтвердіть розподіл IRQ/RSS, потім поверніться до GRO/TSO при потребі.

5) Симптом: Після вимкнення оффлоудів продуктивність впала і CPU скаче

Корінна причина: Ви прибрали батчінг, підвищили частоту пакетів і намацали межу CPU/softirq.

Виправлення: Увімкніть TSO/GSO назад, тримайте LRO вимкненим, можливо залиште GRO увімкненим. Поліпшіть спрямування (RSS), розміри кілець і affinity IRQ.

6) Симптом: Захоплення показує гігантські «пакети» більші за MTU

Корінна причина: GRO/LRO показує злиті skbs у точці захоплення; це не порушення MTU на дроті.

Виправлення: Вимкніть GRO/LRO для вікна захоплення або захоплюйте поза хостом.

7) Симптом: Реплікація зберігання або iSCSI/NFS працює гірше з «більше оптимізацією»

Корінна причина: Зміни патернів backpressure і сплесків через оффлоуди; баги драйвера під тривалими великими сегментами.

Виправлення: A/B тестуйте TSO/GSO; слідкуйте за ретрансмісами і CPU. Якщо вимкнення допомагає, перевірте оновлення firmware/driver і розгляньте локалізацію оффлоудів до VLAN/інтерфейсів зберігання.

Чеклісти / покроковий план

Покроково: доведіть, що оффлоуди — проблема (не просто «інше»)

  1. Базова інформація: зафіксуйте ethtool -k, ethtool -i, ip -s link, nstat.
  2. Відтворіть: запускайте реальне навантаження, не лише iperf. Захопіть p95/p99 затримки, ретрансміси і лічильники помилок.
  3. Одна перемикація: вимкніть спочатку GRO. Повторіть тест. Якщо зміна помітна — рухайтесь далі; якщо ні — відкотіть.
  4. Друга перемикація: вимкніть TSO/GSO. Повторіть тест. Слідкуйте за CPU і softirq.
  5. Визначте обсяг зміни: якщо ламається лише один клас трафіку (овералей, VLAN зберігання), віддавайте перевагу локалізації змін до вузлів або інтерфейсів.
  6. План відкату: напишіть точні команди для відкату і перевірте, що вони працюють.

Чеклист зміни контролю (як не стати інцидентом)

  • Робіть спочатку на одному хості. Потім — на невеликому канарі. Потім — масштаб.
  • Тримайте LRO вимкненим, якщо немає виміряної причини і простого L2/L3 шляху.
  • Не вимикайте все одночасно. GRO і TSO впливають на різні сторони стеку.
  • Відслідковуйте CPU softirq і RX drops після змін. Якщо вони стрибають — ви перемістили вузьке місце.
  • Зберігайте конфіг через systemd link файли або systemd units, а не через rc.local-легенди.
  • Документуйте: інтерфейс, драйвер, прошивка, версія ядра, матриця оффлоудів і виміряний результат.

Чеклист відкату (напишіть це перед будь-якою зміною)

cr0x@server:~$ sudo ethtool -K enp5s0f0 gro on lro off tso on gso on

Значення: Приклад відкату до консервативної бази: тримайте LRO вимкненим, знову увімкніть GRO/TSO/GSO.

Рішення: Якщо відкат не відновлює поведінку, ви дізналися, що оффлоуди не були кореневою причиною. Перестаньте міняти оффлоуди і розширте пошук.

Опціонально: зміна розмірів кілець (тільки якщо лічильники вказують туди)

cr0x@server:~$ sudo ethtool -G enp5s0f0 rx 2048 tx 2048
cr0x@server:~$ sudo ethtool -g enp5s0f0 | egrep 'Current hardware settings|RX:|TX:' -A4
Current hardware settings:
RX:	2048
RX Mini:	0
RX Jumbo:	0
TX:	2048

Значення: Більші кільця зменшують дропи під сплесками, але можуть збільшити буферизацію/затримку.

Рішення: Якщо ваша проблема — «дропи під мікросплесками», це часто правильніше, ніж вимикати GRO.

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

1) Чи варто вимикати GRO/LRO/TSO за замовчуванням на Ubuntu 24.04?

Ні. Стандартні оффлоуди загалом правильні для типової навантаженості. Вимикайте лиш тоді, коли можете показати проблему коректності або вимірювану деградацію продуктивності, пов’язану з оффлоудами.

2) Чому вимкнення оффлоудів іноді усуває «не реальні» втрати пакетів?

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

3) Якщо LRO такий ненадійний, навіщо він існує?

Його створили для пропускної здатності на простіших шляхах, часто в старіших або більш контрольованих середовищах. Сучасні мережі (овералеї, віртуалізація, маршрутизація на хості) зробили його крайові випадки дорожчими, ніж вигоди, для багатьох організацій.

4) Чи завжди «bad checksum» в tcpdump нешкідливий?

Не завжди, але часто це артефакт оффлоуда. Підтвердіть, захопивши поза хостом або тимчасово вимкнувши checksum offload. Якщо проблема відтворюється поза хостом з поганими контрольними сумами — тоді це реальна проблема.

5) У чому практична різниця між TSO і GSO?

TSO — це апаратна TCP-сегментація NIC. GSO — це загальний програмний фреймворк, який дозволяє кернелю сегментувати подібно для інших протоколів або коли апарат не підходить.

6) Чи збільшиться затримка після вимкнення TSO/GSO?

Може бути по-різному. Часто це збільшує роботу CPU і частоту пакетів, що може підвищити чергування під навантаженням. Але воно може знизити сплески і уникнути деяких багів драйверів/тунелів, покращивши хвостову затримку в певних сценаріях.

7) Я вимкнув GRO і захоплення виглядає «нормально» тепер. Чи я виправив продакшн?

Ви виправили спостережуваність. Це цінно, але не те саме, що виправлення продакшн-поведінки. Увімкніть GRO назад після захоплення, якщо у вас немає доказів, що воно викликало видимі користувацькі проблеми.

8) Чи можна відключити оффлоуди лише для VLAN, мосту або тунелю?

Оффлоуди зазвичай налаштовуються на фізичному або віртуальному інтерфейсі. Ви можете застосувати налаштування до інтерфейсу, який термінує ваш трафік (наприклад, фізичний NIC, bond або veth/bridge в деяких випадках), але «по VLAN» гранулярність обмежена і залежить від драйвера.

9) Як зрозуміти, що я CPU-заблоковані після вимкнення оффлоудів?

Слідкуйте за mpstat на предмет високого %soft, перевіряйте /proc/interrupts на баланс, і дивіться на зростання RX drops або rx_no_buffer_count. Якщо вони ростуть, ви поміняли мережеву проблему на проблему обробки хоста.

10) Чи змінює Ubuntu 24.04 самі оффлоуди у порівнянні з 22.04?

Більш значущою зміною є ядро, драйвери і як ваша прошивка NIC взаємодіє з ними. Релізи Ubuntu можуть зрушувати дефолти, але більшість історій «щось змінилося після оновлення» — насправді зрушення в поведінці драйвера/прошивки під тими ж флагами.

Висновок: наступні кроки, які можна впровадити

GRO/LRO/TSO — не лиходії. Це інструменти підвищеної потужності. Якщо ви використовуєте їх, не розуміючи, що вони змінюють, рано чи пізно ви проріжете власну ментальну модель і втратите час у war room.

  1. Пройдіть швидкий план діагностики і вирішіть, чи ви женетеся за коректністю, чи за пропускною здатністю.
  2. Візьміть базу з ethtool -k, nstat, ip -s link та статистиками softirq CPU.
  3. A/B тестуйте по одному перемиканню: GRO спочатку для спостережуваності/прийому, TSO/GSO для передачі/дивних шляхів оверлею.
  4. Збережіть найменшу зміну через systemd .link файл або oneshot unit, і попередньо канаріть її.
  5. Перевірте, що ви не створили вузьке місце CPU і що ретрансміси/дропи дійсно покращилися.

Якщо ви винесете одне правила: тримайте LRO вимкненим, не вимикайте TSO/GSO легковажно, і ставтеся до GRO як до одночасно регулятора продуктивності і джерела помилок спостережуваності. Тестуйте так, ніби має значення.

← Попередня
«Мій CPU не може нагодувати GPU»: правда проти міфу
Наступна →
Сокети як стратегія: чому платформи зараз важливіші за процесори

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