Ви купуєте робочу станцію з «16 ядрами», запускаєте збірку, а графік затримок виглядає як сейсмограф під час невеликої екзистенційної кризи.
Або ви виділяєте блискучий хост EPYC, і одна мікросервіс літає, а інша повзе — той самий код, те саме навантаження, той самий день.
Це ера чіплетів у виробництві: дешевші ядра, більше ядер і топологія, яка безжально покарає ліниві припущення.
Стратегія AMD із чіплетами не просто «покращила продуктивність». Вона воскресила Ryzen як лінійку продуктів, змінивши економіку виробництва — і змінила спосіб,
у який оператори повинні діагностувати вузькі місця, розміщувати пам’ять і фіксувати роботу на ядрах.
Чіплети однією фразою (і чому це важливо)
Чіплетний CPU — це процесор, збудований із кількох менших кристалів (зазвичай кристалів з ядрами плюс окремий кристал вводу/виводу), з’єднаних високошвидкісним інтерконектом.
Якщо ви SRE, перекладіть це так: обчислення модульне, I/O централізоване, і доступ до пам’яті вже не «однорідний», навіть коли ваш планувальник робить вигляд, що це так.
Якщо ви інженер зі зберігання, перекладіть це так: PCIe і контролери пам’яті знаходяться на іншому кристалі, ніж ядра, що роблять контрольні суми, стиск,
ерейзу-кодинг і мережеві операції.
AMD зробила це масовим. І AMD зробила це саме тоді, коли монолітні кристали з великою кількістю ядер ставали надто дорогими для надійного виробництва.
Чіплети були трюком, який дозволив AMD випускати багато ядер з конкурентними частотами і прийнятними маржами, одночасно швидко ітераційно переходячи між поколіннями.
Короткий історичний контекст: конкретні факти, що підготували ґрунт
Декілька фактів важливі, бо пояснюють, чому чіплети були не просто модним вибором дизайну — це був вихід із тупика. Тримайте їх у кишені.
- Перші настільні CPU Ryzen на базі Zen від AMD вийшли в 2017 році, покінчивши з довгим періодом, коли «AMD проти Intel» не була серйозною дискусією за продуктивність у багатьох сегментах.
- Zen 2 (2019) став великим поворотом до чіплетів для масового ринку: обчислювальні ядра перемістилися на кілька менших кристалів, у парі з окремим I/O кристалом на іншому технологічному вузлі.
- I/O кристал у Zen 2 зазвичай був на зрілому вузлі (старший, дешевший, з вищим виходом), тоді як обчислювальні чіплети виготовлялися на передовому вузлі.
- EPYC «Rome» (Zen 2) масштабувався до багатьох чіплетів у серверах, довівши модель на великій кількості ядер раніше, ніж настільні системи повністю усвідомили всі наслідки.
- Infinity Fabric став «хребтом», що зробив модульні обчислення здійсненними без перетворення кожного промаху кешу на катастрофу.
- Економіка виходів стала безжальною на передових вузлах: чим більший кристал, тим вища ймовірність, що дефект зіпсує весь шматок. Менші кристали підвищують корисний вихід з вафлі.
- Чіплети дозволили агресивне бінування продуктів: AMD могла комбінувати різні чіплети ядер і сегментувати SKU без проєктування нового моноліту для кожного випадку.
- Планувальники Windows і Linux мусили наздоганяти: усвідомлення топології має більше значення, коли ядра розділені по кристалах, а контролери пам’яті розташовані окремо.
Історія не в тому, що «AMD вигадала чіплети». Істина в тому, що AMD оперувала ними в масштабі для споживчих і серверних рішень так, що змінила криву ціна/продуктивність.
Як чіплети AMD працюють насправді: CCD, IOD і «трубопровід» між ними
Складові: CCD і IOD
У дизайні чіплетів AMD зазвичай маємо:
- CCD (Core Complex Die): обчислювальний тайл(и). Саме тут розташовані ядра CPU і їхні кеші.
- IOD (I/O Die): тайл, який містить контролери пам’яті, контролери PCIe і часто іншу «некрасиву», але важливу інфраструктуру.
- Інтерконект: Infinity Fabric зв’язує ці кристали.
Операційно це означає, що CPU, який виконує ваш процес, може знаходитися на одному кристалі від контролера пам’яті, що обробляє його DRAM-трафік, і на одному кристалі від PCIe root complex,
який обробляє переривання NVMe. Цей «перехід» швидкий. Він не є безкоштовним.
Топологія: «NUMA, але робіть її непомітною»
NUMA старший за більшість панелей, на які ми дивимося. Але чіплети зробили його релевантним для людей, які раніше ігнорували цю тему.
Навіть у межах одного сокета латентність до пам’яті може відрізнятися залежно від того, на якому CCD знаходиться ваше ядро і який контролер пам’яті (на IOD) обробляє запит.
Практичне визначення: якщо навантаження дружить з кешем, чіплети здебільшого виграшні. Якщо воно чутливе до латентності пам’яті з великою кількістю випадкових доступів,
чіплети можуть перетворитися на податкову тягар, якщо ви не будете обережні з плануванням і виділенням ресурсів.
Infinity Fabric: що дає і за що бере плату
Infinity Fabric — це інтерконект, що зшиває кристали разом. Це не «просто шина». Це екосистема: синхронізація тактів, когерентність
і спосіб, як обчислювальні кристали спілкуються з I/O кристалом і, у багатосокетних системах, потенційно з іншим сокетом.
Практично:
- Кращий випадок: fabric достатньо швидкий, щоб модульність була непомітною, і ви отримуєте багато ядер за хорошу ціну.
- Найгірший випадок: ви плануєте потоки через кристали, рухаєте кеш-лінії і перетворюєте p99-латентність на рису характеру.
Одна цитата, щоб не даватися розслабитися, коли заманеться махнути рукою щодо топології:
Латентність — це податок, який ви платите за кожен запит; пропускна здатність — дивіденд, який ви можете або не зібрати.
— Brendan Gregg (перефразована ідея)
Два жарти, використані відповідально
Жарт 1: Чіплети чудові, бо тепер у вас можуть бути вісім маленьких CPU, які сперечаються про когерентність кешу, замість одного великого CPU, що робить це тихо.
Чому це воскресило Ryzen: виходи, бінування, ритм і сегментація продуктів
Економіка виробництва: менші кристали, кращі виходи
Кажімо прямо: чіплети дозволяють AMD продавати більше придатного кремнію з однієї вафлі. Дефекти трапляються. Це нормально. Важливо, скільки продукту ви зможете врятувати.
З великим монолітним кристалом один дефект може зіпсувати велику площу. З кількома меншими кристалами дефект псує лише один чіплет.
Це змінює все: собівартість на одне корисне ядро, наскільки агресивно можна робити кількість ядер, і скільки SKU можна прибутково випускати.
Це також дозволяє AMD використовувати передові вузли для обчислювальних ядер, утримуючи I/O на зрілому вузлі, який дешевший і часто електрично простіший для аналогових інтерфейсів.
Гнучкість бінування: комбінувати хороші частини в хороші продукти
Чіплети відкривають практичне бінування. Якщо один CCD має трохи гірше ядро, його можна опустити в нижчий SKU. Інший CCD з кращими характеристиками
може піти в SKU з вищими частотами. IOD залишається в тій самій родині. Ця модульність тримає продуктовий стек заповненим без вимоги героїчного виходу.
Також це пояснює появу «дивно хороших» середньорівневих частин, які розганяються, ніби хочуть щось довести: часто вони зроблені з відмінних чіплетів,
які не потрапили в вищий SKU з не-продуктивних причин (інвентар, попит, сегментація).
Швидша ітерація: оновлюйте I/O окремо від ядер (або навпаки)
Завдяки чіплетам AMD може розвивати архітектуру ядер і технологічний вузол, не переробляючи весь I/O підсистему з тією ж швидкістю.
Це зменшує ризик. Також скорочує час виходу на ринок. IOD складний і повний інтерфейсів, які болісні на передовому вузлі.
Для операторів ефект тонкий: ви побачите покоління, де сирі обчислювальні можливості стрибнуть, але латентність пам’яті або поведінка I/O змінюватимуться інакше.
Не робіть припущення «новий CPU» означає «та ж топологія і більше GHz».
Сегментація десктопу і серверу без перевинаходження
AMD може масштабувати ті самі базові блоки у сімействах Ryzen і EPYC, налаштовуючи кількості й можливості I/O під ринки.
Це не лише ефективність бізнесу — це причина, чому Ryzen повернувся з переконливою продуктивністю і чому EPYC став серйозною опцією для дата-центру.
Реальність для операцій: де чіплети допомагають, а де кусають
Де чіплети однозначно вигідні
- Паралельні навантаження: ферми збірки, рендеринг, стиск, шифрування, аналітика, консолідація VM — все, що масштабується по ядрах і терпить варіацію локальності.
- Економічне масштабування: більше ядер за долар часто перекриває трохи гірший p99, за умови чесності щодо вимог до хвостової латентності.
- Доступність і різноманіття SKU: ринок отримає більше «дивно специфічних» CPU, які підходять для певних ролей флоту.
Де чіплети карають
Режим відмови зазвичай не «повільно». Це «непослідовно». Одна прогонка в нормі. Наступна — на 30% гірше. Потім ви перезавантажуєте й усе покращується,
і це переконує всіх, що це був «транзієнт». Це не був транзієнт.
- Планування, яке ігнорує NUMA: потоки й розподіли пам’яті дрейфують по кристалах.
- Переривання, що падають не на ті ядра: NIC/NVMe переривання б’ють по CCD, віддаленому від роботи.
- Конкуренція блокувань між кристалами: спільні структури даних штовхають кеш-лінії по fabric.
- Чутливі до латентності пам’яті навантаження: key-value, трейдингові робочі навантаження, деякі БД і все, що працює з pointer chasing.
Жарт 2: Якщо ваша продуктивність «поліпшується після перезавантаження», вітаю — ви винайшли рулетку топології.
Що робити (загалом)
Ставте топологію в ранг першого класу ресурсу. Це означає:
- Вимірювати латентність і пропускну здатність пам’яті, а не тільки завантаження CPU.
- Фіксувати критичні навантаження й їхню пам’ять в одному NUMA-вузлі, коли можливо.
- Уважно ставитися до налаштувань BIOS, які змінюють частоти fabric, стани живлення і інтерлівінг пам’яті.
- Слідкувати за розподілом переривань і афінітетом черг на NIC/NVMe з великим пропускним навантаженням.
Швидкий план діагностики: знайти вузьке місце до кінця наради
Коли хост Ryzen/EPYC з чіплетами «відчувається не так», у вас немає часу філософствувати. Потрібна швидка тріаж-послідовність, що звузить простір.
Перший крок: підтвердьте топологію й видимість NUMA
- Скільки NUMA-вузлів бачить ОС? Чи відповідають вони очікуванням?
- Чи рівномірно заповнена пам’ять по каналах?
- Чи ядра розподілені по CCD так, щоб планувальник це розумів?
Другий крок: вирішіть, звідки вузьке місце — обчислення, пам’ять чи I/O
- Обчислювально-зав’язане: високий IPC, високе завантаження ядер, стабільний p99.
- Пам’яттю-зав’язане: низький IPC, багато зупинених циклів, багато LLC-miss, нерівномірний NUMA-трафік.
- I/O-зав’язане: черги ростуть, високий iowait, переривання на вузькому наборі CPU, обмеження PCIe, спайки латентності NVMe.
Третій крок: перевірте «топологічні аварії»
- Наванттаження мігрують між NUMA-вузлами (неправильні налаштування cpuset/cgroup або поведінка планувальника).
- Неправильне прив’язування переривань NIC/NVMe.
- Розподіл пам’яті віддалений від потоків, які її використовують (NUMA balancing воює з вами).
Четвертий крок: перевірте налаштування прошивки і поведінку енергоспоживання
- Зв’язування частоти fabric, швидкість пам’яті і стани живлення (C-states, CPPC, P-states).
- Увімкнення/вимкнення SMT для хвостової латентності.
- Детерміновані профілі продуктивності, якщо їх дає ваш постачальник.
П’ятий крок: лише потім торкайтесь налаштувань програми
Якщо топологія неправильна, налаштування програми — це просто театр продуктивності. Виправте розміщення спочатку.
Практичні завдання з командами: підтвердити топологію, виміряти, вирішити
Це завдання, які я насправді виконую, коли підозрюю топологію чіплетів. Кожне містить: команду, що означає її вивід, і рішення.
Припущення: хост Linux. Якщо ви використовуєте іншу ОС, ваш день і так достатньо ускладнений.
Завдання 1: Визначити модель CPU і stepping
cr0x@server:~$ lscpu | egrep 'Model name|Socket|Thread|Core|NUMA|Vendor|CPU\(s\)'
CPU(s): 64
Vendor ID: AuthenticAMD
Model name: AMD EPYC 7xx2 32-Core Processor
Thread(s) per core: 2
Core(s) per socket: 32
Socket(s): 1
NUMA node(s): 4
NUMA node0 CPU(s): 0-15
NUMA node1 CPU(s): 16-31
NUMA node2 CPU(s): 32-47
NUMA node3 CPU(s): 48-63
Значення: Один сокет, 4 NUMA-вузли. Це сигнал топології: локальність пам’яті має значення навіть «в межах одного CPU».
Рішення: Якщо навантаження чутливе до латентності, плануйте NUMA pinning і прив’язку пам’яті; інакше прийміть це і зосередьтесь на пропускній здатності.
Завдання 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
node 0 size: 64512 MB
node 0 free: 60210 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
node 1 size: 64512 MB
node 1 free: 61102 MB
node 2 cpus: 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
node 2 size: 64512 MB
node 2 free: 60001 MB
node 3 cpus: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
node 3 size: 64512 MB
node 3 free: 61234 MB
node distances:
node 0 1 2 3
0: 10 12 12 12
1: 12 10 12 12
2: 12 12 10 12
3: 12 12 12 10
Значення: Пам’ять рівномірно розподілена; матриця відстаней показує локальні й віддалені витрати.
Рішення: Якщо один вузол має значно менше пам’яті (або відсутній), виправте заповнення DIMM або налаштування BIOS interleaving перед тим, як звинувачувати додаток.
Завдання 3: Перевірити швидкість пам’яті та заповнення каналів
cr0x@server:~$ sudo dmidecode -t memory | egrep 'Locator:|Speed:|Configured Memory Speed:|Size:'
Locator: DIMM_A1
Size: 32 GB
Speed: 3200 MT/s
Configured Memory Speed: 3200 MT/s
Locator: DIMM_B1
Size: 32 GB
Speed: 3200 MT/s
Configured Memory Speed: 3200 MT/s
Locator: DIMM_C1
Size: 32 GB
Speed: 3200 MT/s
Configured Memory Speed: 3200 MT/s
Locator: DIMM_D1
Size: 32 GB
Speed: 3200 MT/s
Configured Memory Speed: 3200 MT/s
Значення: Налаштована швидкість відповідає номінальній. Якщо ви бачите 2133/2400 на платформі, що має працювати на 3200, ви тихо платите штраф за латентність і пропускну здатність.
Рішення: Виправте профіль пам’яті в BIOS/сумісність; перевірте змішування DIMM і правила заповнення слотів.
Завдання 4: Подивитись, які CPU забиті перериваннями
cr0x@server:~$ cat /proc/interrupts | head -n 12
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
24: 18423922 0 0 0 0 0 0 0 IR-PCI-MSI 524288-edge nvme0q0
25: 12 0 0 0 0 0 0 0 IR-PCI-MSI 524289-edge nvme0q1
40: 9234411 0 0 0 0 0 0 0 IR-PCI-MSI 1048576-edge enp65s0f0-TxRx-0
41: 34 0 0 0 0 0 0 0 IR-PCI-MSI 1048577-edge enp65s0f0-TxRx-1
Значення: CPU0 отримує велику частку NVMe і NIC черг. Це часто корелює з джитером, спайками softirq і питанням «чому одне ядро на 100%?»
Рішення: Розподіліть IRQ: увімкніть irqbalance (обережно) або вручну встановіть афінітет для критичних черг поруч із NUMA-вузлом навантаження.
Завдання 5: Відобразити пристрій до його NUMA-вузла (локальність NIC/NVMe)
cr0x@server:~$ cat /sys/class/net/enp65s0f0/device/numa_node
1
Значення: Цей NIC локальний для NUMA-вузла 1.
Рішення: Розмістіть найактивніші потоки обробки мережі на CPU вузла 1 і розгляньте прив’язку буферів/обробки мережі там.
Завдання 6: Перевірити ширину/швидкість PCIe для «чому моє NVMe повільне?»
cr0x@server:~$ sudo lspci -s 41:00.0 -vv | egrep 'LnkCap:|LnkSta:'
LnkCap: Port #0, Speed 16GT/s, Width x4, ASPM L1, Exit Latency L1 <4us
LnkSta: Speed 8GT/s (downgraded), Width x4 (ok)
Значення: Пристрій може працювати на 16GT/s, але зараз працює на 8GT/s. Це реальна втрата пропускної здатності і підвищення латентності.
Рішення: Перевірте налаштування BIOS PCIe, riser-и, проводку слота та ретаймери. Не «оптимізуйте» софт для проблеми апаратного погодження.
Завдання 7: Перевірити поведінку частоти CPU під навантаженням (стати енергетичні стани важливі)
cr0x@server:~$ sudo apt-get -y install linux-tools-common linux-tools-generic >/dev/null
cr0x@server:~$ sudo turbostat --quiet --Summary --interval 1 --num_iterations 3
Time_Of_Day_Seconds Avg_MHz Busy% Bzy_MHz IRQ SMI PkgTmp PkgWatt
54421.9 2875 62.3 4012 812 0 61 142.3
54422.9 2910 64.1 3988 799 0 62 145.0
54423.9 2842 60.8 4020 821 0 61 141.7
Значення: Ви бачите ефективні MHz і busy MHz. Якщо Bzy_MHz падає при помірному навантаженні, вас кусають обмеження енергопостачання чи температури.
Рішення: Для чутливих до латентності сервісів вибирайте детермінований енергопрофіль і розгляньте обмеження глибоких C-states.
Завдання 8: Перевірити розподіл пам’яті процесу по NUMA-вузлах
cr0x@server:~$ pidof memcached
24831
cr0x@server:~$ numastat -p 24831
Per-node process memory usage (in MBs) for PID 24831 (memcached)
Node 0 Node 1 Node 2 Node 3 Total
Huge 0.0 0.0 0.0 0.0 0.0
Heap 5120.0 1024.0 980.0 990.0 8114.0
Stack 8.0 8.0 8.0 8.0 32.0
Значення: Heap розподілений по вузлах. Це може бути нормально для пропускної здатності; може бути катастрофою для хвостової латентності, якщо потоки здебільшого на одному вузлі.
Рішення: Забиндьте процес і його пам’ять до одного вузла (або шардуйте по вузлах). Або явно запускайте кілька інстансів на кожен NUMA-вузол.
Завдання 9: Спостерігати віддалені vs локальні звернення до пам’яті (kernel NUMA stats)
cr0x@server:~$ egrep 'numa_(hit|miss|foreign|interleave|local|other)' /proc/vmstat
numa_hit 428112233
numa_miss 2219921
numa_foreign 1941122
numa_interleave 0
numa_local 426331900
numa_other 1920333
Значення: numa_miss і numa_foreign показують крос-вузлові алокації. Швидке зростання під час інциденту — червоний прапор.
Рішення: Дослідіть міграцію процесу, автоматичне NUMA balancing і політику пам’яті. Виправте розміщення перед тим, як міняти код.
Завдання 10: Підтвердити пінування планувальника і cgroup (чи дрейфує сервіс?)
cr0x@server:~$ systemctl show -p AllowedCPUs -p AllowedMemoryNodes myservice.service
AllowedCPUs=
AllowedMemoryNodes=
Значення: Порожнє означає «без обмежень». Якщо ви очікували pinning, його немає.
Рішення: Додайте CPUAffinity/AllowedCPUs і обмеження по вузлах пам’яті, або використайте cpuset cgroup для примусового розміщення.
Завдання 11: Закріпити бенчмарк на один NUMA-вузол, щоб виміряти вплив локальності
cr0x@server:~$ numactl --cpunodebind=1 --membind=1 bash -lc 'python3 - <
Значення: Це грубий «touch memory» тест. Повторіть з різними прив’язками вузлів. Якщо часи сильно відрізняються, локальність має значення для вашого класу навантаження.
Рішення: Якщо розбіжності великі, проєктуйте розгортання навколо NUMA-шардування або явного біндінгу.
Завдання 12: Виміряти інтерконект/топологію за допомогою hwloc (візуалізувати чіплети)
cr0x@server:~$ sudo apt-get -y install hwloc >/dev/null
cr0x@server:~$ lstopo-no-graphics | head -n 30
Machine (256GB total)
Package L#0
NUMANode L#0 (P#0 64GB)
L3 L#0 (32MB)
L2 L#0 (512KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0
PU L#0 (P#0)
PU L#1 (P#1)
NUMANode L#1 (P#1 64GB)
L3 L#1 (32MB)
L2 L#1 (512KB) + L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1
PU L#2 (P#16)
PU L#3 (P#17)
Значення: Ви бачите NUMA-вузли і групування L3. У дизайнах з чіплетами ці групи часто збігаються з межами CCD/CCX.
Рішення: Використайте цей вигляд для проєктування наборів CPU для сервісів: тримайте «балакучі» потоки в межах одного L3-домена коли можливо.
Завдання 13: Виявити «пінг-понг» кеш-ліній між кристалами за допомогою perf (підказка про contention)
cr0x@server:~$ sudo perf stat -e cycles,instructions,cache-misses,LLC-load-misses -p 24831 -- sleep 10
Performance counter stats for process id '24831':
38,112,004,991 cycles
52,984,222,101 instructions # 1.39 insn per cycle
812,113,992 cache-misses
204,113,100 LLC-load-misses
10.003221861 seconds time elapsed
Значення: Високі LLC misses і відносно низький IPC можуть вказувати на пам’яттєвий тиск. Поєднуйте це з NUMA-статистикою, щоб відрізнити «залежність від пам’яті» від «поганого розміщення».
Рішення: Якщо LLC misses стрибають при рознесенні потоків по вузлах, перенаправте pinning; якщо misses властиві алгоритму, змініть макет даних або кешування.
Завдання 14: Перевірити поведінку автоматичного NUMA balancing у Linux
cr0x@server:~$ cat /proc/sys/kernel/numa_balancing
1
Значення: 1 означає, що автоматичне NUMA balancing ввімкнено. Воно може допомагати загальним хостам, але також спричиняти непередбачувані міграції для чутливих до латентності сервісів.
Рішення: Якщо ви робите явне pinning, розгляньте вимкнення механізму (системно або через ізоляцію навантажень) і виміряйте до/після.
Завдання 15: Перевірити стан transparent hugepages (компроміс латентність vs пропускна здатність)
cr0x@server:~$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
Значення: THP увімкнено завжди. Це може бути добре для пропускної здатності, але додавати спайки латентності під час collapse/defrag у деяких навантаженнях.
Рішення: Для сервісів, чутливих до хвостової латентності, проведіть бенчмарки з THP=never або madvise і вирішіть за p99, а не за середнім.
Завдання 16: Швидко перевірити насичення пропускної здатності пам’яті (vmstat + mpstat)
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
2 0 0 8123456 123456 987654 0 0 1 3 900 2200 45 8 45 2 0
8 0 0 8012345 123456 988000 0 0 0 0 1100 5200 62 10 28 0 0
9 0 0 7999999 123456 987900 0 0 0 0 1200 6000 65 11 24 0 0
7 0 0 7988888 123456 987800 0 0 0 0 1180 5900 64 10 26 0 0
Значення: Багато runnable-потоків (r) з низьким iowait (wa) свідчать про CPU/пам’ять тиск, а не про сховище. Поєднайте з perf/numastat, щоб визначити, чи це пропускна здатність чи латентність.
Рішення: Якщо CPU зайнятий, але IPC низький і NUMA-miss зростає, виправте розміщення; якщо ні — розгляньте зменшення конкурентності або поліпшення кеш-поведінки.
Три корпоративні міні-історії з практики
Міні-історія 1: Інцидент, спричинений неправильним припущенням
Команда перенесла чутливе до латентності API з старого двосокетного Intel-хоста на одно сокетний EPYC-бокс. План міграції був простий:
«Ті самі ядра, та сама RAM, менше сокетів — отже має бути простіше». Навіть їхній лоад-тест спочатку виглядав нормально.
У продакшені — ні. p95 тримався, p99 стрибав, і on-call отримав класичну комбінацію алертів: підвищена затримка запитів, нормальне завантаження CPU, без очевидного I/O насичення.
Дашборд виглядав спокійно так, як тихий ліс, в якому ви раптом розумієте, що заблукали.
Неправильне припущення було в тому, що «один сокет» — означає «однорідність». Сервіс мав великий in-memory кеш і кілька дуже гарячих м’ютексів.
Планувальник охоче мігрував потоки між NUMA-вузлами всередині сокета, алокації пам’яті дрейфували, і кеш-лінії стрибали по fabric.
Середня латентність не кричала. Хвостова латентність робила це.
Виправлення було нудним, але рішучим: закріпити сервіс на NUMA-вузлі, прив’язати пам’ять до цього вузла і запускати два інстанси замість одного великого.
Також перемістили NIC-переривання на той самий вузол. p99 стабілізувався. Команда здобула новий вид скромності: скромність у питаннях топології.
Постмортем-дія, що справді допомогла: додати перевірки NUMA і IRQ-affinity до чекліста готовності, а не в «вікно продвинутих налаштувань», яке ніхто не читає.
Міні-історія 2: Оптимізація, що обернулась проти
Сервіс з інтенсивним використанням сховища (уявіть: метадані, контрольні суми, стиск) був CPU-залежним у піку. Хтось запропонував просту зміну:
«Розкиньмо робітників по всіх ядрах, щоб максувати паралелізм». Вони також ввімкнули агресивне авто-шкальовання по CPU — звісно.
Пропускна здатність покращилася в мікробенчмарках. Графіки були святкові. Потім черговий батч-job спрацював, і все пішло шкереберть:
черги збільшилися, p99 подвоївся, а система почала поводитися ніби в ній є генератор випадкових чисел у планувальнику.
Відкат стався через крос-дійне contention. Розкидання робітників по CCD дало більше паралелізму, так, але також посилило трафік спільного стану.
«Глобальна» черга і кілька спільних хеш-таблиць стали точками когерентності. Інтерконект виконав свою роботу; навантаження покарало його за те, що він був корисним.
Виправлення було контратинтуїтивним, якщо вірити лише в число ядер: зменшити крос-дійний трафік, шардувати черги по NUMA-вузлах і закріпити пул робітників.
Деякі робітники пішли простоювати, і загальне завантаження CPU впало. Латентність покращилася. Пропускна здатність залишилася прийнятною. Графіки стали менш «вражаючими»,
що в продакшені — добре.
Справжній урок: на CPU з чіплетами «більше ядер» не рівнозначно «більше спільного стану». Якщо ваш алгоритм припускає дешеве шарингування, ви тримаєте гранату за чеку.
Міні-історія 3: Нудна, але правильна практика, що врятувала ситуацію
Інша організація мала змішаний флот: робочі станції Ryzen для CI і сервери EPYC для продакшену. У них була рутинна, на перший погляд нудна звичка:
кожна нова апаратна партія проходила стандартизований набір валідацій топології, й результати зберігалися в картці активу.
Якось кварталом приїхала партія серверів з тонкою помилкою в BIOS від вендора: інтерлівінг пам’яті і енергетичний профіль віддавали перевагу
енергоефективності над детермінованою латентністю. Нічого «зламаного». POST пройшов. Машини навіть пройшли базовий burn-in.
Але їхній валідаційний прогін це виявив: латентність пам’яті була вищою за попередню партію, а під навантаженням поведінка частот була нестабільною.
Оскільки в них були базові показники, вони мали докази. Вони не сперечалися через відчуття; вони сперечалися через вимірювання.
Виправили це до продакшену: підлаштували BIOS-профілі, уніфікували прошивку і перевірили ще раз. Партія приєдналася до флоту без шуму.
Ніяких інцидентів. Ніяких екстрених нарад. Нічних археологій «чому p99 дрейфує?» не було.
Нудна практика перемагає, бо масштабується. Героїзм — ні. Якщо ви хочете надійності, інституціоналізуйте непривабливі перевірки.
Типові помилки: симптом → корінь → виправлення
1) Симптом: p99-латентність стрибає, тоді як CPU% виглядає нормальним
Корінь: потоки мігрують по NUMA-вузлах; алокації пам’яті стають віддаленими; зростає когерентний трафік між CCD/IOD.
Виправлення: закріпити CPU і пам’ять (cpuset/numactl), шардувати по NUMA-вузлу і перевірити за numastat -p і лічильниками NUMA у /proc/vmstat.
2) Симптом: одне ядро завантажене, softirq високі, мережеві латентності джитерові
Корінь: афінітет IRQ звівся до одного CPU (часто CPU0), або черги некоректно налаштовані.
Виправлення: розподілити переривання, вирівняти черги з локальністю NUMA, перевірити за /proc/interrupts і NUMA-вузлом пристрою в sysfs.
3) Симптом: NVMe-пропускна здатність нижча, ніж очікувалось після зміни апаратури
Корінь: PCIe-лінк знизив свою швидкість (downgraded), неправильний слот або налаштування BIOS обмежують швидкість.
Виправлення: перевірити lspci -vv LnkSta проти LnkCap; виправити слот/riser/BIO S; повторно тестувати перед тим, як міняти файлові налаштування.
4) Симптом: продуктивність варіюється від прогону до прогону з тим самим навантаженням
Корінь: автоматичне NUMA balancing, дрейф планувальника або різні початкові патерни алокацій.
Виправлення: забезпечити примусове розміщення; вимкнути/налаштувати NUMA balancing для сервісу; перевірити, повторивши закріплений бенчмарк.
5) Симптом: «Більше потоків» зменшує пропускну здатність
Корінь: крос-дійна contention на блокуваннях; спільні черги; «пінг-понг» кеш-ліній.
Виправлення: шардувати стан по NUMA-вузлах/CCD; зменшити глобальні блокування; використовувати per-node worker pools; вимірювати LLC misses і contention на блокуваннях.
6) Симптом: стабільна пропускна здатність, але періодичні довгі паузи
Корінь: collapse/defrag THP, звільнення пам’яті або переходи частоти/енергоспоживання.
Виправлення: протестувати THP=never/madvise; забезпечити достатній запас; встановити детермінований енергетичний профіль для сервісів, чутливих до латентності.
7) Симптом: база даних виглядає «CPU-залежною», але IPC низький
Корінь: фактично обмеження по латентності пам’яті; віддалена пам’ять; погана локальність між чіплетами.
Виправлення: закріпити і біндити пам’ять; перемістити найгарячіші дані у макети, дружні до кешу; вимірювати за допомогою perf + NUMA-статистики.
Контрольні списки / покроковий план для розгортань, дружніх до чіплетів
Покроковий план: прийняття нового вузла Ryzen/EPYC
- Задокументуйте топологію: зафіксуйте
lscpu, кількість NUMA-вузлів, кількість ядер/потоків. - Перевірте заповнення пам’яті: використайте
dmidecode; підтвердіть очікувану швидкість і збалансовані канали. - Базуйте поведінку NUMA: збережіть
numactl --hardwareматрицю відстаней і розміри пам’яті по вузлах. - Базуйте поведінку частот: виміряйте під навантаженням за
turbostatі зафіксуйте «звичайні» діапазони. - Перевірте PCIe-лінки: перевірте узгоджену швидкість/ширину NIC і NVMe за
lspci -vv. - Підтвердіть локальність пристроїв: зафіксуйте NUMA-вузол пристроїв через sysfs для топ-NIC і NVMe.
- Визначте стратегію IRQ: вирішіть irqbalance чи ручний афінітет; задокументуйте це і протестуйте.
- Визначте розміщення навантажень: вирішіть, які сервіси потребують pinning, а які можуть плавати.
- Встановіть тест: запустіть один pinned memory-touch або bandwidth тест на вузол і збережіть результати.
- Впроваджуйте поступово в продакшен: канарка з репрезентативними навантаженнями; стежте p99 і NUMA-miss.
Чекліст: коли хост з чіплетами має нез’ясовану латентність
- Чи є несподівані NUMA-вузли або нерівномірні розміри пам’яті вузлів?
- Чи сконцентровані IRQ на невеликій множині CPU?
- Чи NIC/NVMe на іншому NUMA-вузлі, ніж найактивніші потоки?
- Чи PCIe-лінк натренований на нижчу швидкість?
- Чи numa_miss/numa_foreign зростають під час інциденту?
- Чи планувальник має дозвіл мігрувати сервіс по вузлах?
- Чи змінювалися прошивка або налаштування BIOS (профіль енергоспоживання, інтерлівінг пам’яті, SMT)?
Чекліст: проєктування для передбачуваної продуктивності
- Шардуйте по NUMA-вузлу, коли стан великий і доступ до нього частий.
- Тримайте IRQ локальними до обчислень, що обробляють пакети й завершення I/O.
- Уникайте глобальних блокувань, які змушують крос-дійний когерентний трафік.
- Віддавайте перевагу обмеженій конкурентності перед «використати всі ядра», коли p99 має значення.
- Бенчмаркуйте з pinning увімкненим і вимкненим, щоб зрозуміти вашу чутливість до топології.
FAQ
1) Чи завжди чіплети швидші за монолітні CPU?
Ні. Чіплети часто виграють за ціною/продуктивністю і масштабністю. Монолітні дизайни можуть перемагати за однорідною латентністю і деякими шаблонами кеш-кохезії.
Вибирайте за поведінкою навантаження, а не за маркетинговими епітетами.
2) Яка найбільша операційна різниця з CPU на чіплетах?
Топологія стає функцією продуктивності. NUMA і усвідомлення домену кешу мають значення там, де раніше можна було це ігнорувати.
3) Чому AMD розділила обчислення і I/O на різні кристали?
Бо це економічно й технічно розумно: ядра CPU виграють від передових вузлів; I/O виграє від зрілих вузлів і стабільної аналогової поведінки.
Розділення покращує вихід і знижує ризик на покоління.
4) Який найпоширеніший «податок чіплетів» в реальних системах?
Віддалені звернення до пам’яті і «пінг-понг» кеш-ліній між кристалами. Обидва проявляються як хвостова латентність, а не обов’язково середнє уповільнення.
5) Чи варто вимикати SMT на Ryzen/EPYC для латентності?
Іноді. SMT може покращити пропускну здатність, але погіршити хвостову латентність при високій конкуренції або коли ви вже чутливі до топології.
Виміряйте з навантаженням, схожим на продакшен; не робіть це за принципом.
6) Автоматичне NUMA balancing — добре чи погано?
Добре для загальних хостів. Ризикове для ретельно закріплених сервісів, чутливих до латентності, бо воно може мігрувати сторінки в спосіб, що додає джитер.
Якщо ви робите явний pinning, розгляньте вимкнення — після вимірювань.
7) Чому дві «однакові» системи Ryzen дають різні бенчмарки?
Поширені причини: різне заповнення пам’яті (канали), різні BIOS-профілі енергоспоживання, різні налаштування зв’язування fabric/пам’яті,
проблеми з погодженням PCIe, і різні стани планувальника/афінітету IRQ.
8) Як чіплети впливають на навантаження збереження даних?
Стек зберігання поєднує CPU, пам’ять і PCIe. Якщо NVMe і NIC переривання потрапляють далеко від потоків, що роблять стиск/контрольні суми,
ви платите додаткову латентність і накладні витрати когерентності. Вирівняйте локальність пристроїв, афінітет IRQ і розміщення робітників.
9) Чи роблять чіплети віртуалізацію складнішою?
Не складнішою, але менш поблажливою. Якщо ви перевантажуєте і дозволяєте vCPU мігрувати по NUMA-доменах, ви отримаєте ефекти «галасного сусіда» і непередбачуваний p99.
NUMA-aware розміщення VM і pinning CPU допомагають.
10) Що варто базувати на кожній новій чіплет-платформі?
Топологію NUMA і розподіл пам’яті, стан PCIe-лінків, поведінку частот під навантаженням і знімок розподілу IRQ.
Якщо ви не можете виявити дрейф, ви не зможете його запобігти.
Висновок: наступні кроки, які справді знижують ризик
Чіплети AMD воскресили Ryzen, змінивши виробничу рівняння: менші кристали з ядрами, кращі виходи, модульне масштабування і швидша ітерація.
Це бізнес-рішення перетворилось на операційну реальність: топологія тепер — частина продуктивності, а не примітка в кінці документа.
Наступні кроки, які варто зробити цього тижня, а не «як-небудь»:
- Виберіть один сервіс, чутливий до латентності, і сьогодні виміряйте його NUMA-розміщення:
numastat -p, лічильники NUMA у/proc/vmstatі/proc/interrupts. - Канарка стратегія pinning: забиндьте CPU + пам’ять до вузла, вирівняйте IRQ, порівняйте p99. Тримайте зміну маленькою і вимірюваною.
- Інституціоналізуйте тест прийняття апаратури: топологія, швидкість пам’яті, тренування PCIe-лінків і перевірка частот.
- Припиніть довіряти середнім: проблеми продуктивності чіплетів часто — це хвостові проблеми, замасковані під середні показники.
Чіплети — не пастка. Це угода: ви отримуєте багато ядер за розумну ціну, і натомість погоджуєтесь трактувати топологію як реальну.
Підпишіться на контракт. Ваш p99 скаже вам дякую.