Деякі проблеми з продуктивністю відчуваються особисто. Ви купили багатоядерний Ryzen або EPYC, підключили швидкі NVMe, виділили ОЗП, щоб соромити минулок—а система все одно поводиться так, ніби тягне піаніно сходами. Графіки показують, що CPU «доступний», диски «в порядку», мережа «в нормі», але навантаження вперто повільне й стрибкоподібне.
Зазвичай тут у розмову вступає Infinity Fabric. Не як компонент, на який можна вказати викруткою, а як міжз’єднання, яке вирішує, чи співпрацюють ваші чиплети як злагоджена команда реагування на інциденти — або сваряться, як рев’ю змін о 16:55.
Що таке Infinity Fabric насправді (і чим воно не є)
Infinity Fabric — це масштабована архітектура міжз’єднання від AMD — комунікаційна система, що переміщує дані й трафік когерентності між ядрами CPU, кешами, контролерами пам’яті та I/O. На сучасних Ryzen і EPYC воно є клеєм, який змушує підхід із чиплетами поводитись як один логічний CPU (переважно).
Якщо ви прийшли з ери монолітних кристалів, уявіть це так: «CPU» тепер — невеликий кампус. Є кілька будівель (core chiplets), центральна службова будівля (I/O die або контролери пам’яті залежно від покоління) та мережа між ними. Infinity Fabric — це та внутрішня мережа — комутатори, лінки, протоколи, арбітрація і синхронізація. Коли вона працює добре, ви її не помічаєте. Коли ні — у вас стрибає затримка й неоднорідно падає пропускна здатність.
Чим воно не є: одним годинником, одним шинним конвеєром або магічним перемикачем «fast». Це багаторівнева система з різними доменами: ядро‑до‑ядра, ядро‑до‑пам’яті, ядро‑до‑I/O і трафік когерентності. Найбільш релевантна для ops частина — це те, що певні шляхи затримки перетинають його, і його ефективна швидкість часто залежить від того, як ви налаштуєте пам’ять, такти, політику NUMA і налаштування BIOS щодо живлення.
Чому це має турбувати ops і інженерів з продуктивності
Бо більшість виробничих навантажень не є «CPU‑bound» так, як це уявляють бенчмарки. Вони прив’язані до затримки. Вони чутливі до промахів кешу. Вони багато спілкуються між потоками. Вони чутливі до NUMA. Це купа мікросервісів, що ускладнюють один одному життя. І Infinity Fabric частково відповідає за затримки кожного разу, коли дані мають переміститися між чиплетами, регіонами пам’яті або I/O‑шляхами.
Саме тут команди помиляються: середня завантаженість CPU виглядає нормальною, але хвостова затримка псує все. Або вузол бази даних чудово працює на одному хості й дивно гірше на іншому «однаковому» хості. Або сервер з усіма NVMe видає меншу пропускну здатність, ніж у специфікації. Фабрика не показується на більшості дашбордів, але вона має вплив.
Жарт №1 (коротко й промовисто): Infinity Fabric — як офісний Wi‑Fi — ніхто його не закладає в бюджет, всі його звинувачують, і якось воно завжди причетне.
Факти та історія, які справді важливі в 2026
Ось конкретні факти й контекст, що змінюють підхід до діагностики:
- Infinity Fabric з’явилося як об’єднуюче міжз’єднання в еру Zen, щоб масштабувати ядра й I/O без монолітних кристалів. Цей архітектурний зсув пояснює, чому «однакова сім’я CPU» може поводитися дуже по‑різному між поколіннями й SKU.
- Чиплети зробили затримку міжз’єднання ключовим фактором продуктивності. У монолітних кристалах латентність між ядрами була здебільшого «на кристалі». З чиплетами частина трафіку тепер має переходити через фабрику, і ваше навантаження або це витримує, або ні.
- У багатьох поколінь Ryzen тактові частоти fabric (FCLK) і пам’яті (MCLK) були зв’язані для кращої латентності. Розв’язування дозволяє підняти частоту пам’яті, але додає латентності, що карає за хвостові‑чутливі робочі навантаження.
- EPYC масштабувався шляхом додавання CCD і великого I/O die. Це покращує відбракування та кількість ядер, але одночасно створює топологію: деякі ядра «ближчі» до певної пам’яті та I/O ніж інші.
- NUMA не опційний на багато‑CCD системах EPYC. Ви можете вдавати UMA, але апаратне забезпечення не погодиться. Планувальник Linux спробує, але він не читає вашу думку — або локальність кеша.
- За замовчуванням BIOS часто оптимізований під енергію/теплоспоживання, а не детерміновану латентність. Якщо ви запускаєте БД, торгові системи або сховища, «енергозберігаючий» режим може непомітно означати «стриби затримки».
- Віртуалізація посилює помилки топології. VM, що простягається через NUMA‑вузли, може перетворити гарний CPU на генератор віддаленої пам’яті з побічним прибутком у вигляді втрачених пакетів.
- Оновлення прошивки й AGESA історично змінювали поведінку пам’яті/фабрики — іноді покращуючи стабільність, іноді змінюючи характеристики продуктивності. «Та сама апаратна частина» до й після прошивки не завжди однакова.
Ментальна модель: бюджети затримки й шаблони трафіку
Коли кажуть «вузьке місце Infinity Fabric», зазвичай мають на увазі одну з трьох речей:
- Додана затримка: запити частіше переходять межі чиплетів або NUMA‑доменів, продовжуючи критичний шлях для промахів кешу, блокувань і коду з інтенсивним IPC.
- Обмежена пропускна здатність: багато ядер генерують достатньо трафіку пам’яті, що міжз’єднання й контролери пам’яті насичуються, викликаючи затримки через черги.
- Джиттер: стани енергозбереження, зміни частот або конкуренція створюють непередбачуваний час обслуговування; середні значення можуть виглядати нормально, а p99 — як місце злочину.
На практиці більшість інцидентів — суміш: навантаження стає важким на віддалену пам’ять (латентність) і відчуває конкуренцію на міжз’єднанні (пропускна здатність) і отримує хвостові піки через міграції планувальника (джиттер). Ваше завдання — визначити, що домінує, і вибрати найменш ризикове рішення.
Думайте в категоріях шаблонів трафіку:
- Балакучі багатопотокові додатки (спільні блокування, черги, паузи GC) страждають, коли потоки перескакують між CCD/NUMA‑вузлами.
- In‑memory бази даних дбають про затримку пам’яті й передбачуваність доступу. Віддалена пам’ять перетворює «швидку ОЗП» на «повільнішу ОЗП з додатковими кроками».
- Сервери зберігання турбуються про локальність I/O і переривань. Погана афініті призводить до того, що NVMe‑переривання обробляються ядрами, далекими від кореня PCIe, додаючи затримку й витрачені кеш‑ресурси.
- Хости віртуалізації дбають про розміщення. Один хост може працювати ідеально, поки «шумний сусід» VM не розсуне потоки по вузлах і не перетвориться на стрес‑тест фабрики.
FCLK/UCLK/MCLK і «податок синхронізації»
На багатьох платформах AMD ви зустрінете три тактові домени, що впливають на поведінку пам’яті й фабрики:
- MCLK: такт пам’яті (пов’язаний із DDR data rate).
- UCLK: такт контролера пам’яті.
- FCLK: такт фабрики.
Залежно від покоління і параметрів BIOS вони можуть працювати 1:1 або в співвідношеннях (часто 1:2), коли ви піднімаєте частоту пам’яті. Пастка в тому, що вищі DDR‑швидкості виглядають як «більше пропускної здатності», тоді як зміна співвідношення додає латентності, що карає ті самі робочі навантаження, які для вас важливі в продакшені.
Ось практичний переклад для ops:
- Якщо ваше навантаження чутливе до затримки (бази даних, кеші, RPC‑сервіси), зазвичай краще стабільна конфігурація, що зберігає низьколатентні відносини між тактами фабрики й пам’яті, навіть якщо пікова пропускна здатність трохи нижча.
- Якщо ваше навантаження стрімінгове/обмежене пропускною здатністю (деякі аналітичні роботи, великі послідовні скани), підвищення пропускної здатності може допомогти — поки не зустрінете конкуренцію в інших місцях.
«Податок синхронізації» проявляється як погіршення латентності доступу до пам’яті, а не обов’язково зниження вимірюваної пропускної здатності. Саме тому ви можете «оптимізувати» швидкість DDR, а потім дивуватися, чому p99 став гіршим. Ви не зробили пам’ять швидшою. Ви зробили систему менш передбачуваною.
NUMA, чиплети, CCD/CCX: куди їздять ваші цикли
Особливо на EPYC топологія — це доля. Ядра групуються в CCD (core chiplet dies), і вони підключені до I/O die, де знаходяться контролери пам’яті та PCIe. Кожен CCD має свій L3 кеш; доступ через CCD коштує дорожче, ніж залишатися локально.
NUMA виступає як кілька вузлів. Навіть на одному фізичному сокеті у вас може бути кілька NUMA‑вузлів залежно від налаштувань BIOS (режими NPS, відображення CCD). Тоді Linux намагається планувати потоки й виділяти пам’ять так, щоб зменшити віддалені звернення. Ключове слово — «намагається». Ваше навантаження, ваш pinning і cgroup‑політики можуть зруйнувати ці спроби за секунди.
Поширені патерни, що б’ють:
- Міграція потоків: потоки перескакують між ядрами/NUMA‑вузлами через рішення планувальника, втрачаючи локальність кеша й збільшуючи віддалені доступи до пам’яті.
- Пам’ять виділена на неправильному вузлі: процес стартує на одному вузлі, виділяє пам’ять там, а потім планується на іншому. Тепер кожен доступ до пам’яті — поїздка через фабрику.
- Переривання на неправильних ядрах: NIC/NVMe‑переривання, які обробляються далекими ядрами, підвищують I/O‑затримку й марну витрату CPU‑циклів.
PCIe і I/O: інша половина історії
Infinity Fabric — це не лише «CPU‑до‑RAM». Це також частина того, як обробляється I/O. На багатьох системах PCIe‑пристрої підключені до конкретних root complex, пов’язаних із певними NUMA‑вузлами (або принаймні доменами локальності). Якщо обробка переривань і потоки обробки зберігання виконуються «далеко» від шляху PCIe, ви платите додатковою затримкою й CPU‑накладними витратами.
Тут інженерія зберігання зустрічається з топологією CPU. Ваш NVMe RAID, ZFS, SPDK‑таргет або Ceph OSD технічно «швидкі», але якщо найгарячіші потоки заплановані на віддалених ядрах і їхні виділення пам’яті потрапляють на неправильний NUMA‑вузол, ви фактично будували низьколатентну систему зберігання й потім пустили її мальовничим шляхом.
Практичні завдання: 12+ команд, що вони означають, що вирішувати
Це реальні завдання, які можна виконати на Linux‑хості. Вони не скажуть «Infinity Fabric сумне», але покажуть, чи підривають вас топологія, локальність пам’яті, такти або переривання.
Завдання 1: Визначити модель CPU та базову топологію
cr0x@server:~$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
CPU(s): 128
Thread(s) per core: 2
Core(s) per socket: 64
Socket(s): 1
NUMA node(s): 4
Model name: AMD EPYC 7xx3 64-Core Processor
NUMA node0 CPU(s): 0-31
NUMA node1 CPU(s): 32-63
NUMA node2 CPU(s): 64-95
NUMA node3 CPU(s): 96-127
Що це означає: У вас чотири NUMA‑вузли на одному сокеті. Це вже попереджувальний знак: локальність пам’яті має значення.
Рішення: Якщо ви запускаєте навантаження, чутливе до затримки, плануйте прикріплення процесів/VM до кожного NUMA‑вузла і вирівнюйте виділення пам’яті. Якщо ви думали, що це UMA, припиніть це робити.
Завдання 2: Показати деталі відстаней NUMA
cr0x@server:~$ numactl --hardware
available: 4 nodes (0-3)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
node 0 size: 128798 MB
node 0 free: 97211 MB
node 1 cpus: 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
node 1 size: 128829 MB
node 1 free: 99102 MB
node 2 cpus: 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
node 2 size: 128813 MB
node 2 free: 100118 MB
node 3 cpus: 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
node 3 size: 128820 MB
node 3 free: 99654 MB
node distances:
node 0 1 2 3
0: 10 16 16 16
1: 16 10 16 16
2: 16 16 10 16
3: 16 16 16 10
Що це означає: Локальна відстань вузла — 10, віддалена — 16. Це суттєва різниця в латентності для «гарячої» пам’яті.
Рішення: Для баз даних і серверів зберігання ставте до кожного NUMA‑вузла як до «міні‑сокета». Тримайте гарячі потоки та їхню пам’ять на одному вузлі, коли це можливо.
Завдання 3: Візуалізувати топологію за допомогою hwloc
cr0x@server:~$ lstopo-no-graphics --no-io
Machine (512GB total)
NUMANode L#0 (P#0 128GB)
Package L#0
L3 L#0 (32MB)
L2 L#0 (512KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
...
NUMANode L#1 (P#1 128GB)
Package L#0
L3 L#1 (32MB)
...
Що це означає: Ви бачите, як ядра відображаються на L3‑сегменти й NUMA‑вузли. Це ваш план розміщення.
Рішення: Використовуйте це, щоб вибирати CPU‑набори для сервісів і інтерпретувати питання «чому цей потік мігрував?» пізніше.
Завдання 4: Перевірити стан автоматичного балансування NUMA в ядрі
cr0x@server:~$ cat /proc/sys/kernel/numa_balancing
1
Що це означає: Автоматичне балансування NUMA увімкнено. Воно може допомогти загальним навантаженням, але також може викликати міграцію сторінок (джиттер) для сервісів, чутливих до затримки.
Рішення: Для затримко‑чутливих прикріплених навантажень розгляньте вимкнення системного автоматичного балансування та керування розміщенням вручну — або принаймні протестуйте обидва варіанти. Не вгадуйте.
Завдання 5: Спостерігати політику NUMA і розміщення пам’яті для працюючого процесу
cr0x@server:~$ pidof postgres
2147
cr0x@server:~$ numactl --show --pid 2147
policy: default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
cpubind: 0
nodebind: 0
membind: 0
Що це означає: Цей процес фактично обмежений вузлом 0 для CPU і пам’яті. Це добре — якщо навантаження поміщається в пропускну здатність і кеш вузла 0.
Рішення: Якщо процес великий і обмежений пропускною здатністю, подумайте про шардінг по вузлах. Якщо він чутливий до затримки — тримайте його компактним і локальним.
Завдання 6: Виміряти тенденції локального й віддаленого доступу пам’яті за допомогою numastat
cr0x@server:~$ numastat -p 2147
Per-node process memory usage (in MBs) for PID 2147 (postgres)
Node 0 56321.4
Node 1 112.7
Node 2 95.3
Node 3 88.9
Total 56618.3
Що це означає: Пам’ять здебільшого на вузлі 0. Якщо потоки також виконуються на вузлі 0 — все в порядку. Якщо ні — ви платите латентністю фабрики.
Рішення: Якщо бачите суттєву частку пам’яті на віддалих вузлах — виправляйте pinning або стартове розміщення. Для сервісів запускайте їх під numactl або налаштовуйте системd CPU/NUMA політики.
Завдання 7: Перевірити надмірну міграцію сторінок (джиттер)
cr0x@server:~$ grep -E 'pgmigrate|numa' /proc/vmstat | head
numa_pte_updates 1829401
numa_huge_pte_updates 0
numa_hint_faults 219884
numa_hint_faults_local 171102
numa_pages_migrated 48211
pgmigrate_success 47998
pgmigrate_fail 213
Що це означає: Сторінки мігруються. Невелика міграція — нормальне явище при увімкненому балансуванні; велика міграція під навантаженням свідчить, що планувальник і політика пам’яті борються з вашим навантаженням.
Рішення: Якщо p99 затримки корелюють зі сплесками міграцій, зменшіть міграцію: прикріпіть потоки, виділяйте пам’ять локально, розгляньте вимкнення автобалансування NUMA для цього класу хостів.
Завдання 8: Перевірити режим частоти CPU (латентність vs енергія)
cr0x@server:~$ cpupower frequency-info | sed -n '1,18p'
analyzing CPU 0:
driver: amd-pstate-epp
CPUs which run at the same hardware frequency: 0
hardware limits: 1.50 GHz - 3.70 GHz
available cpufreq governors: performance powersave
current policy: frequency should be within 1.50 GHz and 3.70 GHz.
The governor "powersave" may decide which speed to use
current CPU frequency: 1.74 GHz
Що це означає: У вас політика «powersave». Це підходить для пакетних задач, але часто погано для хвостової латентності й відгуку I/O.
Рішення: Для вузлів, чутливих до затримки, встановіть governor у performance (і перевірте температури). Робіть це як політику по ролі, а не як одноразове „латання“.
Завдання 9: Встановити performance governor (контрольована зміна)
cr0x@server:~$ sudo cpupower frequency-set -g performance
Setting cpu: 0
Setting cpu: 1
Setting cpu: 2
Setting cpu: 3
Що це означає: Ви зменшили варіативність масштабування частот.
Рішення: Повторно виміряйте p95/p99 затримки та пропускну здатність. Якщо стало краще — зафіксуйте це в профілі для цього класу систем.
Завдання 10: Перевірити NUMA‑локальність PCIe пристрою (важливо для NVMe/NIC)
cr0x@server:~$ lspci -nn | grep -E 'Non-Volatile|Ethernet' | head -n 3
01:00.0 Non-Volatile memory controller [0108]: Samsung Electronics Co Ltd NVMe SSD Controller [144d:a808]
41:00.0 Non-Volatile memory controller [0108]: Samsung Electronics Co Ltd NVMe SSD Controller [144d:a808]
81:00.0 Ethernet controller [0200]: Mellanox Technologies MT28908 Family [ConnectX-6] [15b3:1017]
cr0x@server:~$ cat /sys/bus/pci/devices/0000:01:00.0/numa_node
0
Що це означає: Цей NVMe‑пристрій локальний до NUMA‑вузла 0 (або принаймні ядро так вважає). Якщо ваші I/O‑потоки виконуються на вузлі 3 — ви винайшли віддалений I/O.
Рішення: Вирівнюйте обробку IRQ і робочі потоки зі NUMA‑вузлом пристрою. Для серверів з кількома пристроями розгляньте черги/воркери для кожного вузла.
Завдання 11: Переглянути розподіл IRQ (локальність переривань)
cr0x@server:~$ grep -E 'nvme|mlx5' /proc/interrupts | head -n 6
47: 12841 11993 12110 11888 PCI-MSI 1048576-edge nvme0q0
48: 42112 39877 40655 39221 PCI-MSI 1048577-edge nvme0q1
92: 11822 12031 11760 11911 PCI-MSI 524288-edge mlx5_comp0
93: 12203 12188 12002 12244 PCI-MSI 524289-edge mlx5_comp1
Що це означає: IRQ‑и потрапляють на невелику множину CPU (тут — перші кілька). Це може бути нормально; може бути й фатально, якщо ті CPU не локальні щодо пристрою або зайняті.
Рішення: Якщо ви бачите „гарячі“ IRQ або обробку на неправильному вузлі — змініть афініті або використайте irqbalance з NUMA‑усвідомленими налаштуваннями. Потім перевірте латентність.
Завдання 12: Прикріпити IRQ до CPU локального NUMA‑вузла (точково)
cr0x@server:~$ cat /proc/irq/47/smp_affinity_list
0-3
cr0x@server:~$ sudo sh -c 'echo 0-31 > /proc/irq/47/smp_affinity_list'
cr0x@server:~$ cat /proc/irq/47/smp_affinity_list
0-31
Що це означає: Ви розширили множину CPU, на яких може виконуватися IRQ, до ЦП 0–31 (часто вузол 0). Це покращує локальність, якщо пристрій на вузлі 0.
Рішення: Повторно протестуйте I/O‑затримку під навантаженням. Якщо стало краще — зафіксуйте це через udev/systemd‑скрипти (обережно) або налаштуйте irqbalance.
Завдання 13: Перевірити сигнали латентності пам’яті за допомогою perf (стежити за простоями циклів)
cr0x@server:~$ sudo perf stat -e cycles,instructions,cache-misses,LLC-load-misses -p 2147 -- sleep 10
Performance counter stats for process id '2147':
18,421,334,112 cycles
12,102,884,551 instructions # 0.66 insn per cycle
221,433,112 cache-misses
98,331,220 LLC-load-misses
10.001112123 seconds time elapsed
Що це означає: Низький IPC із великою кількістю промахів останнього рівня кешу може вказувати на тиск латентності пам’яті — часто посилений віддаленими доступами пам’яті на топологіях з великою роллю фабрики.
Рішення: Якщо IPC падає під навантаженням і ви підозрюєте віддалену пам’ять — перевірте NUMA‑статистику й розміщення. Не поспішайте з висновком «потрібно оновити CPU».
Завдання 14: Підтвердити стан Transparent Huge Pages (взаємодіє з міграцією/затримками)
cr0x@server:~$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
Що це означає: THP увімкнено завжди. Іноді це добре; іноді це викликає сплески затримок через дефрагментацію або поведінку виділення, особливо в змішаних навантаженнях.
Рішення: Для баз даних дотримуйтесь рекомендацій для конкретного ПЗ. Якщо не знаєте — тестуйте під реальним навантаженням; не повторюйте уривчасто «вимкнути THP» або «завжди THP» без підтвердження.
Завдання 15: Перевірити, чи процес не скаче між CPU (міграція)
cr0x@server:~$ pidstat -t -p 2147 1 5
Linux 6.8.0 (server) 01/10/2026 _x86_64_ (128 CPU)
12:00:01 PM UID TGID TID %usr %system %CPU CPU Command
12:00:02 PM 26 2147 2147 8.00 2.00 10.00 4 postgres
12:00:02 PM 26 2147 2161 6.00 1.00 7.00 37 postgres
12:00:02 PM 26 2147 2162 5.00 1.00 6.00 92 postgres
Що це означає: Потоки виконуються на CPU 4, 37, 92 — ймовірно на різних NUMA‑вузлах. Це не автоматично погано, але для бази даних, чутливої до затримки, — це червоний прапорець.
Рішення: Якщо продуктивність непослідовна, обмежте БД одним вузлом (або набором вузлів з явним шардінгом) і протестуйте повторно.
Завдання 16: Перевірити тиск пропускної здатності пам’яті за сигналами на зразок pcm (фолбек: vmstat)
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
12 0 0 987654 12345 456789 0 0 2 18 9000 22000 55 10 33 2 0
18 0 0 982110 12345 456792 0 0 0 12 9800 26000 62 12 24 2 0
Що це означає: Висока кількість переключень контексту й runnable‑потоків може вказувати на конкуренцію (блокування, планування), що погіршується, коли потоки розкидані по NUMA‑вузлам. Це не остаточно, але підказка.
Рішення: Поєднайте це з перевірками розміщення NUMA. Якщо конкуренція збігається з розсіюванням по вузлам — звужуйте афініті.
Швидкий план діагностики
Це версія для «pager дзвонить». У вас немає часу ставати мікроархітектором, але є час припинити кровотечу.
По‑перше: Доведіть, чи справа в локальності/топології
- Перевірте кількість NUMA‑вузлів і відображення (
lscpu,numactl --hardware). Якщо NUMA>1, припускайте, що локальність важлива, поки не доведено інше. - Перевірте розповсюдження процесів по CPU (
pidstat -t,ps -o psr). Якщо гарячі потоки виконуються по далеких вузлах — підозрюйте латентність через фабрику. - Перевірте розміщення пам’яті (
numastat -p). Якщо пам’ять здебільшого на одному вузлі, а потоки на іншому — ви знайшли ймовірного винуватця.
По‑друге: Шукайте джерела джиттера, що підсилюють витрати фабрики
- Governor CPU / p‑states (
cpupower frequency-info). Політика «powersave» на вузлах, чутливих до затримки — легка перемога (за умови контролю температури). - NUMA‑міграції (
/proc/vmstatміграції та hint fault). Висока міграція під навантаженням часто корелює з хвостовими сплесками. - THP/поведінка дефрагментації (стан THP, рекомендації для робочого навантаження). Це не завжди пов’язано з фабрикою, але взаємодіє з латентністю.
По‑третє: Підтвердьте локальність I/O (зберігання та мережа)
- NUMA‑вузол пристрою (
/sys/bus/pci/devices/.../numa_node). - Розподіл IRQ по CPU (
/proc/interrupts, налаштування афініті). Обробка на неправильному вузлі — класичний фаєрфаг «чому NVMe повільний». - Глибина черги / модерація переривань (параметри пристрою, але почніть з підтвердження, що не перевантажене одне ядро).
Якщо ви зробите лише одну річ у першу годину: зробіть навантаження локальним — вирівняйте CPU, пам’ять і I/O‑переривання — і протестуйте повторно. Це найпоширеніший «фабрикою сформований» режим відмови і найшвидший для виправлення.
Поширені помилки: симптом → корінь проблеми → виправлення
1) Симптом: Велика середня пропускна здатність, жахливий p99 затримки
Корінь проблеми: Міграція потоків і віддалені доступи пам’яті між NUMA‑вузлами; фабрика додає латентність і збільшує варіативність.
Виправлення: Прикріпіть гарячі потоки до NUMA‑вузла, зв’яжіть пам’ять локально (systemd CPU/NUMA політики або numactl), і зменшіть міграції (налаштуйте/вимкніть автобалансування NUMA для цього класу).
2) Симптом: «Підвищили швидкість пам’яті» і продуктивність стала гіршою
Корінь проблеми: Розв’язування FCLK/UCLK/MCLK або зміна співвідношення підвищили латентність пам’яті; пропускна здатність могла зрости, але критичний шлях латентності постраждав.
Виправлення: Віддавайте перевагу стабільним низьколатентним профілям пам’яті для затримко‑чутливих навантажень. Перевіряйте на реальних p99 метриках, а не лише на синтетичній пропускній здатності.
3) Симптом: Бенчмарки NVMe в порядку, але виробнича I/O‑затримка стрибкоподібна
Корінь проблеми: IRQ‑и обробляються на нелокальних CPU, або робочі потоки зберігання заплановані далеко від кореня PCIe; додатковий хоп через фабрику і промахи кешу.
Виправлення: Вирівняйте афініті IRQ і робочі потоки з локальністю пристрою; розгляньте модель черг на рівні NUMA‑вузла. Перевіряйте під реальним рівнем конкурентності.
4) Симптом: Неконсистентна продуктивність VM на хостах «з тим же CPU»
Корінь проблеми: Різні BIOS‑налаштування NUMA (режими NPS), інтерлевінг пам’яті або прошивки, що змінюють топологію і поведінку фабрики.
Виправлення: Стандартизуйте BIOS‑профілі та прошивки; фіксуйте топологію через lscpu/lstopo при провізії; забезпечте NUMA‑усвідомлене планування і прикріплення VM.
5) Симптом: Завантаження CPU низьке, але сервіс повільний
Корінь проблеми: Стояння циклів на пам’яті (віддалена пам’ять, промахи кешу), конкуренція блокувань, посилена крос‑вузловим плануванням, або накладні витрати на I/O‑переривання на неправильних ядрах.
Виправлення: Використайте perf stat та NUMA‑статистику, щоб підтвердити простої; змініть розміщення; зменшіть крос‑вузлове шарування; виправте локальність IRQ.
6) Симптом: «Це лише один сокет, тому NUMA не має значення»
Корінь проблеми: Топології чиплетів створюють NUMA‑подібну поведінку всередині одного сокета; Linux відкриває це як NUMA‑вузли не просто так.
Виправлення: Розглядайте одно‑сокетні multi‑CCD системи як NUMA‑системи. Внесіть локальність у свої інструкції та планування ємності.
Три корпоративні міні-історії з польових робіт
Міні‑історія 1: Інцидент через хибне припущення
У них був «простий» шлюз зберігання: кілька EPYC‑серверів, швидка мережа, NVMe‑кеш і userspace I/O‑стек. У стейджингу все летіло. У продакшені — були стрибки: хвостова латентність різко зростала під піком, і on‑call дивився на чисті графіки дисків і мережі, ніби Grafana його газлайтить.
Хибне припущення було тонким: «один сокет = рівномірна пам’ять». Команда трактувала коробку як плоский пул ядер і ОЗП. Вони дозволили ядру вільно планувати, і дозволили I/O‑потокам “плавати”, бо «Linux зробить правильно». Linux зробив розумно. Навантаженню ж потрібне було конкретне рішення.
NVMe‑пристрої PCIe були локальні до одного NUMA‑вузла, але найзавантаженіші потоки завершення часто працювали на іншому. Кожне I/O завершення включало хоп через фабрику, плюс промахи кешу, бо найгарячіші структури даних жили в іншому L3. За низького навантаження це не помітно, при високій конкуренції — критично.
Вони виправили це трьома змінами: (1) прикріпили I/O‑потоки до CPU, локальних до контролерів NVMe, (2) прив’язали виділення пам’яті для цих потоків до того самого вузла, (3) встановили афініті IRQ, щоб завершення не падали на випадкові CPU. Латентність стабілізувалася, пропускна здатність зросла, і on‑call перестав бачити фантомні проблеми після обіду.
Міні‑історія 2: Оптимізація, що зіграла зле
Платформна команда хотіла «безкоштовної продуктивності» на флоті серверів застосунків. План: підвищити частоту пам’яті в BIOS. Інструмент вендора показав стабільну роботу, burn‑in пройшов, і синтетичні бенчмарки виглядали добре. Вони розгортали хвилями, бо були обережні — просто оптимістичні.
Потім інцидент: p99 API‑латентність виросла, а не зменшилася. Не по всій системі. Лише деякі сервіси, переважно ті, що використовували багато дрібних in‑memory структур і часто передавали керування між потоками. Завантаження CPU трохи впало (що виглядало «добре», якщо не знати подробиць), але час відгуку став гіршим.
Постмортем був неприємний: нові налаштування пам’яті перевели систему в інше тактове співвідношення, що збільшило ефективну латентність доступу до пам’яті. Пропускна здатність покращилася. Латентність погіршилася. Робочі навантаження були чутливі до хвостової латентності, тож затримка, пов’язана з фабрикою, стала помітною в метриках.
Вони відкатили «апгрейд» пам’яті і провели тести з двома профілями: один для пакетних завдань з високою пропускною здатністю, інший для низьколатентних сервісів. Зрештою стандартизували профілі за ролями. Налаштування продуктивності перестало бути універсальним «збільшити число» завданням і стало тим, чим воно має бути: інженерією, орієнтованою на навантаження.
Міні‑історія 3: Нудна але правильна практика, що врятувала день
Фінансова компанія запускала сервіс, чутливий до затримки, на EPYC. Вони нічого екстраординарного не робили. Але у них була дисципліна: для кожної ролі сервера — базова конфігурація BIOS, базова конфігурація ядра і невеликий «звіт по топології», зафіксований при провізії й збережений із записом активу.
Одного ранку після планового вікна обслуговування підвищилася хвостова латентність на підмножині вузлів. Не катастрофічно, але достатньо для тривог. On‑call порівняв два звіти по топології: NUMA‑лэйаут змінився. Той самий номер моделі, та сама кількість RAM, але налаштування BIOS змінило розбиття NUMA. Поведінка планувальника і локальність пам’яті змінилися, фабрика почала працювати більше.
Вони повернули BIOS‑профіль до відомого‑хорошого базового, перезавантажили уражені вузли, і проблема зникла. Без героїчних зусиль. Без «глибокого занурення в ядро». Просто контроль конфігурації й спостережуваність.
Жарт №2: Найкращий фікс продуктивності іноді — це таблиця в spreadsheet. Не кажіть розробникам, інакше вони почнуть просити зведені таблиці.
Чек-листи / покроковий план
Чек‑лист: Перед тим як щось налаштовувати
- Збережіть виводи
lscpu,numactl --hardwareіlstopo-no-graphicsдля класу вузла. - Підтвердіть, що версії BIOS/прошивки узгоджені по флоту для порівнянних вузлів.
- Визначте метрики успіху: p50/p95/p99 затримки, пропускна здатність, помилки, CPU‑витрати на запит, і (для зберігання) IOPS при заданій затримці.
- Запустіть тест, що відтворює навантаження. Синтетика підходить для підказок; вона не ваш acceptance‑тест.
Покроково: Зробити сервіс NUMA‑адекватним (менший ризик)
- Виберіть цільовий NUMA‑вузол на основі доступних CPU/пам’яті і локальності пристроїв (NVMe/NIC).
- Прикріпіть потоки сервісу до CPU цього вузла (systemd
CPUAffinity=або обгортка). - Прив’яжіть виділення пам’яті до цього вузла (
numactl --membindабо systemd NUMA‑політики, якщо використовуються). - Виправте локальність IRQ, щоб переривання пристрою потрапляли на локальні CPU.
- Протестуйте під навантаженням, порівняйте хвостову затримку і цикли CPU на запит.
- Лише потім чіпайте такти пам’яті, підсилення або налаштування енергоспоживання — бо вони можуть покращити середні значення й тихо зіпсувати хвости.
Покроково: Діагностувати регресію продуктивності «схожу на фабрику» після зміни
- Підтвердьте, що змінилося: профіль BIOS, прошивка, версія ядра, мікрокод, налаштування пам’яті, правила розміщення VM.
- Порівняйте виводи топології (NUMA‑вузли, відображення CPU) до/після зміни.
- Перевірте міграції й розповсюдження планування (
pidstat -t,/proc/vmstatміграції,numastat -p). - Перевірте governor CPU і політику p‑state; відновіть попередню політику, якщо потрібно.
- Перевірте розподіл IRQ і NUMA‑вузол пристрою; поверніть афініті, якщо воно з’їхало.
- Якщо потрібно — відкатуйте швидко. Якщо зміну треба залишити — впровадьте контролі локальності, щоб компенсувати.
Питання і відповіді (FAQ)
1) Чи є Infinity Fabric «те саме» що NUMA?
Ні. NUMA — це модель, видима програмному забезпеченню: час доступу до пам’яті залежить від того, який вузол володіє пам’яттю. Infinity Fabric — це апаратне міжз’єднання, яке часто робить ці відмінності реальними на системах AMD з чиплетами.
2) Чому я бачу кілька NUMA‑вузлів на односокетному EPYC‑сервері?
Тому що в сокеті є кілька чиплетів і доменів локальності. Ядро показує це, щоб планувальник і аллокатор пам’яті могли приймати кращі рішення. Ігнорування цього дозволене, але недешеве.
3) Чи варто вимикати автоматичне NUMA‑балансування ядра?
Іноді. Для змішаних загальних навантажень воно може допомогти. Для прикріплених, чутливих до затримки сервісів воно може давати накладні витрати на міграцію сторінок і джиттер. Тестуйте обидва варіанти на канарковому хості з продакшн‑подібним навантаженням.
4) Чи завжди швидша DDR покращує продуктивність на Ryzen/EPYC?
Ні. Швидша DDR може підвищити пропускну здатність, але якщо вона змінює тактові співвідношення або підвищує ефективну латентність, деякі навантаження погіршаться — особливо ті, що чутливі до хвостової латентності й шляхів промахів кешу.
5) Як зрозуміти, чи шкодить мені віддалена пам’ять?
Шукайте невідповідність: потоки працюють на одному вузлі, а виділення пам’яті на інших (pidstat + numastat -p). Також стежте за підвищеними міграціями сторінок і низьким IPC із високою кількістю LLC‑промахів.
6) Чи може віртуалізація приховати ефекти Infinity Fabric?
Вона може приховати причину і посилити біль. Якщо VM простягається через NUMA‑вузли, віддалені доступи до пам’яті можуть бути частими. Правильна експозиція vNUMA, pinning і розмір VM важливі на EPYC.
7) Чи це стосується лише CPU‑bound навантажень?
Часто більше стосується I/O і змішаних навантажень, бо локальність переривань і патерни доступу до пам’яті домінують у хвостовій поведінці. «Проста» низька завантаженість CPU не означає «швидко».
8) Який найефективніший операційний контроль?
Розміщення, усвідомлене топологією: тримайте гарячі потоки, їхню пам’ять і переривання пристроїв в одному домені локальності. Це зменшує затримки, джиттер і марні CPU‑витрати.
9) Чи варто завжди прикріплювати все?
Ні. Надмірне прикріплення може спричинити нерівномірне навантаження, голодування й погану утилізацію. Прикріплюйте те, що чутливе до затримки або володіє I/O‑шляхами. Пакетні задачі й фонові роботи залишайте гнучкими.
10) Який підхід надійності для такого налаштування?
Використовуйте контрольовані експерименти, канарки і профілі за ролями. Якщо не можете швидко відкотити — ви не «налаштовуєте», ви ризикуєте.
Наступні кроки, які можна зробити цього тижня
Практичний план, що не зламає флот:
- Зробіть інвентаризацію топологій по типах вузлів: зберігайте виводи
lscpu/numactl/lstopoз записом активу. - Виберіть один сервіс, чутливий до латентності, і зробіть його NUMA‑локальним (CPU + пам’ять + локальність IRQ). Виміряйте p99 і CPU‑витрати.
- Стандартизуйте BIOS і політики ядра за ролями (латентність vs пропускна здатність vs пакетна). «Один профіль на все» — шлях до сюрпризів.
- Додайте два дашборди: (a) індикатори віддаленої пам’яті/міграцій (vmstat‑похідні, NUMA‑статистика), (b) розподіл IRQ по CPU і головні споживачі.
- Напишіть рунбук з швидкими кроками діагностики вище. Мета — не боготворити Infinity Fabric; мета — перестати дивуватися топології.
Цитата, яку варто тримати на видному місці, бо вона охоплює всю тему: «Надія — це не стратегія.» — генерал Гордон Р. Салліван