Чіплети AMD: трюк, який воскресив Ryzen

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

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

Це ера чіплетів у виробництві: дешевші ядра, більше ядер і топологія, яка безжально покарає ліниві припущення.
Стратегія AMD із чіплетами не просто «покращила продуктивність». Вона воскресила Ryzen як лінійку продуктів, змінивши економіку виробництва — і змінила спосіб,
у який оператори повинні діагностувати вузькі місця, розміщувати пам’ять і фіксувати роботу на ядрах.

Чіплети однією фразою (і чому це важливо)

Чіплетний CPU — це процесор, збудований із кількох менших кристалів (зазвичай кристалів з ядрами плюс окремий кристал вводу/виводу), з’єднаних високошвидкісним інтерконектом.

Якщо ви SRE, перекладіть це так: обчислення модульне, I/O централізоване, і доступ до пам’яті вже не «однорідний», навіть коли ваш планувальник робить вигляд, що це так.
Якщо ви інженер зі зберігання, перекладіть це так: PCIe і контролери пам’яті знаходяться на іншому кристалі, ніж ядра, що роблять контрольні суми, стиск,
ерейзу-кодинг і мережеві операції.

AMD зробила це масовим. І AMD зробила це саме тоді, коли монолітні кристали з великою кількістю ядер ставали надто дорогими для надійного виробництва.
Чіплети були трюком, який дозволив AMD випускати багато ядер з конкурентними частотами і прийнятними маржами, одночасно швидко ітераційно переходячи між поколіннями.

Короткий історичний контекст: конкретні факти, що підготували ґрунт

Декілька фактів важливі, бо пояснюють, чому чіплети були не просто модним вибором дизайну — це був вихід із тупика. Тримайте їх у кишені.

  1. Перші настільні CPU Ryzen на базі Zen від AMD вийшли в 2017 році, покінчивши з довгим періодом, коли «AMD проти Intel» не була серйозною дискусією за продуктивність у багатьох сегментах.
  2. Zen 2 (2019) став великим поворотом до чіплетів для масового ринку: обчислювальні ядра перемістилися на кілька менших кристалів, у парі з окремим I/O кристалом на іншому технологічному вузлі.
  3. I/O кристал у Zen 2 зазвичай був на зрілому вузлі (старший, дешевший, з вищим виходом), тоді як обчислювальні чіплети виготовлялися на передовому вузлі.
  4. EPYC «Rome» (Zen 2) масштабувався до багатьох чіплетів у серверах, довівши модель на великій кількості ядер раніше, ніж настільні системи повністю усвідомили всі наслідки.
  5. Infinity Fabric став «хребтом», що зробив модульні обчислення здійсненними без перетворення кожного промаху кешу на катастрофу.
  6. Економіка виходів стала безжальною на передових вузлах: чим більший кристал, тим вища ймовірність, що дефект зіпсує весь шматок. Менші кристали підвищують корисний вихід з вафлі.
  7. Чіплети дозволили агресивне бінування продуктів: AMD могла комбінувати різні чіплети ядер і сегментувати SKU без проєктування нового моноліту для кожного випадку.
  8. Планувальники 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

  1. Задокументуйте топологію: зафіксуйте lscpu, кількість NUMA-вузлів, кількість ядер/потоків.
  2. Перевірте заповнення пам’яті: використайте dmidecode; підтвердіть очікувану швидкість і збалансовані канали.
  3. Базуйте поведінку NUMA: збережіть numactl --hardware матрицю відстаней і розміри пам’яті по вузлах.
  4. Базуйте поведінку частот: виміряйте під навантаженням за turbostat і зафіксуйте «звичайні» діапазони.
  5. Перевірте PCIe-лінки: перевірте узгоджену швидкість/ширину NIC і NVMe за lspci -vv.
  6. Підтвердіть локальність пристроїв: зафіксуйте NUMA-вузол пристроїв через sysfs для топ-NIC і NVMe.
  7. Визначте стратегію IRQ: вирішіть irqbalance чи ручний афінітет; задокументуйте це і протестуйте.
  8. Визначте розміщення навантажень: вирішіть, які сервіси потребують pinning, а які можуть плавати.
  9. Встановіть тест: запустіть один pinned memory-touch або bandwidth тест на вузол і збережіть результати.
  10. Впроваджуйте поступово в продакшен: канарка з репрезентативними навантаженнями; стежте 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 скаже вам дякую.

← Попередня
PostgreSQL проти CockroachDB: висока доступність без драми — або з новими видами болю
Наступна →
Обмеження потужності та Boost: чому ваша GPU поводиться, наче має свою голову

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