Маркетингові ядра: коли число в назві вводить в оману

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

Ви купуєте сервер «64‑ядра», переносите на нього latency‑чутливе навантаження — і… нічого не пришвидшується. Ба більше: стає дивніше: деякі запити летять, інші гальмують,
а дашборди сперечаються між собою. Хтось питає: «Чи ми обмежені CPU?» — і раптом половина кімнати бенчмарчить, інша половина домовляється з фінансами.

Саме тут слово «ядро» перестає бути технічним іменником і перетворюється на маркетинговий дієслово. Число в SKU — не гарантія пропускної здатності,
латентності чи навіть передбачуваного планування. Це підказка. Інколи корисна. Часто — пастка.

Що насправді означає «маркетингове ядро»

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

У сучасних системах «кількість ядер» може означати будь‑що з наведеного нижче залежно від того, хто розмовляє:

  • Фізичні ядра (окремі CPU‑ядра з власними конвеєрами та приватними кешами L1/L2).
  • Апаратні потоки (SMT/Hyper‑Threading: два або більше планованих потоків, що ділять ресурси виконання одного ядра).
  • Ефективні ядра vs продуктивні ядра (гетерогенні дизайни, де «ядро» навіть може бути різного класу).
  • vCPU (хмарна або віртуалізаційна абстракція, що може відображатися на апаратні потоки, тайм‑слайси або щось посередині).
  • «Еквівалентні ядра» (вендор‑ або ліцензійно‑визначені одиниці, що мають нормалізувати різні архітектури, часто смішно некоректні).

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

Ще одна відверта істина: найдорожчі помилки трапляються коли кількість ядер точна, але нерелевантна. У вас можуть бути реальні ядра й при цьому
вузьким місцем бути затримка пам’яті, мережа, сховище, конкуренція за блокування, паузи GC або ліцензування по ядрам.

Чому числа в назві вводять в оману (і як саме)

1) SMT/Hyper‑Threading: «подвоєння CPU» без подвоєння продуктивності

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

Якщо ваше навантаження вже насичує порти виконання ядра (поширено в tight loops, крипто, стисненні, деяких DB‑операторах), SMT допомагає менше.
Якщо навантаження затримується на пам’яті або через промахи у передбаченні гілок, SMT може допомогти більше. Але слово «може» багато значить.

Оманливий момент: дашборди та описи інстансів у хмарі можуть рахувати апаратні потоки як CPU. Це роздуває числа й змінює очікування.

2) Гетерогенні ядра: P‑ядра та E‑ядра не взаємозамінні

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

Якщо ви запускаєте latency‑критичні сервіси, вам важлива найгірша поведінка планування. Якщо запускаєте батчі — загальна пропускна здатність на ватт.
«Загальна кількість ядер» змішує це в одне число, яке легко друкувати й важко аналізувати.

3) Turbo, обмеження потужності та частота при «всіх ядрах»

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

Кількість ядер взаємодіє з енергоспоживанням. Багато CPU не можуть одночасно тримати всі ядра на високій частоті. Додайте AVX‑важкі інструкції — і частота може впасти ще більше.
Купівля «більше ядер» може принести вам нижчу швидкість на ядро під саме тим навантаженням, заради якого ви його купили.

4) NUMA: потайний податок при «більше сокетів, більше ядер»

Додаючи сокети, ви додаєте NUMA‑доменів. Пам’ять, приєднана до одного сокета, повільніша при доступі з іншого. Ця пеня проявляється у підвищеній
хвостовій латентності, посиленні конкуренції за блокування та в «швидко в microbench, повільно в проді» загадках.

NUMA — не баг; це фізика й упаковка. Помилка — думати, що ваше ПЗ автоматично знає про NUMA, коли воно цього не робить.

5) Хмарні vCPU: число, яке може означати «апаратний потік», «квоту» або «time share»

У хмарі vCPU часто відповідає апаратному потоку. Але продуктивність залежить від конфлікту на хості, варіацій моделі CPU та політики планувальника.
Деякі типи інстансів дають виділені ядра; інші — «переважно ваші, поки хтось інший не шумить».

Найменування часто натякає на стабільну базову продуктивність, якої насправді немає. Треба вимірювати.

6) Ліцензування: «ядра» як одиниця виставлення рахунків, а не обчислень

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

Якщо ви запускаєте пропрієтарні СУБД, аналітичні рушії чи віртуалізацію, ліцензування може домінувати в апаратних витратах. «Кількість ядер» стає бюджетною проблемою
ще до того, як перетворитися на фічу продуктивності.

Жарт №1: «64‑ядровий» чип — як «сімейний» пакет чіпсів: технічно правда, але не каже, наскільки він насичує.

Факти & історичний контекст, які можна використовувати в аргументах

Нижче короткі, конкретні тези, які можна кидати на зустрічах зі складання розмірів, щоб відвести рішення від магічного мислення.

  1. Ранні x86 «війни за MHz» закінчилися, бо частота впиралась у стіни тепла й енергії. Індустрія переключилась на багатоядерність, бо такти не росли як раніше.
  2. Hyper‑Threading масово з’явився в епоху Intel Pentium 4. Він підвищував пропускну здатність у деяких навантаженнях, але також загострив проблеми планування й конкуренції за кеш.
  3. NUMA існує десятиліттями в серверних платформах. Змінилось те, що звичайні коробки отримали кілька сокетів і chiplet‑дизайн, приносячи NUMA‑поведінку в «звичайні» кластери.
  4. Chiplet‑дизайн збільшив кількість ядер швидше, ніж пропускну здатність пам’яті. Більше ядер на сокет не означає автоматично більше пам’яті на ядро або пропускної здатності на ядро.
  5. «Ядро» стало одиницею ліцензування в корпоративному софті задовго до того, як ним користувались у хмарному прайсингу. Саме тому деякі ліцензійні умови все ще припускають фізичні сокети й ядра.
  6. AVX та інші широкі векторні інструкції можуть викликати зниження частоти. «Той самий CPU, ті самі ядра» можуть працювати повільніше залежно від набору інструкцій.
  7. Покращення планувальника Linux для гетерогенних ядер є відносно новими. Версія ядра має значення, коли ви змішуєте P‑ядра/E‑ядра або big.LITTLE‑подібні дизайни.
  8. Серії інстансів у хмарі часто приховують варіації моделей CPU під однаковою назвою. Дві інстанси з однаковим числом vCPU можуть мати суттєво різну IPC і поведінку кешів.
  9. Бенчмарки типу SPEC підштовхували вендорів оптимізувати під конкретні навантаження. Це не шахрайство; це реальність. Але це означає, що ваше навантаження може поводитися інакше, ніж заголовні графіки.

Режими відмов: як команди обманюються в продакшні

«Оманливі кількості ядер» — це не теоретична скарга. Це опиняється в он‑коллах, бо команди розмірюють системи за неправильною змінною.
Ось шаблони, що повторюються в постмортемах.

Помилка «однакова кількість ядер»

Команди вважають, що 32 ядра на CPU A = 32 ядра на CPU B. Насправді ви можете порівнювати:
різний IPC, різні розміри кешу, різні канали пам’яті, різну частоту при всіх ядрах і різну топологію.
«Ті самі ядра» перетворюються на регрес продуктивності під прикрасою закупівлі.

Неправильне прочитання «CPU високий»

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

Плутанина з контейнерними квотами

В Kubernetes под може бути придушений CPU‑лімітами навіть якщо вузол здебільшого простий. Розробники бачать низьке завантаження вузла й думають, що є запас.
Тим часом CFS‑квота тихо душить пропускну здатність і розтягує хвостову латентність.

Сюрприз NUMA

Сервіс «швидкий на маленьких інстансах, повільний на великих.» Це підпис NUMA. Більші машини додають домени пам’яті; потоки додатку
блукають між ними; локальність кешів руйнується; латентність стрибає. Більше ядер — гірша поведінка.

Бумеранг ліцензування

Хтось обирає SKU з найбільшою кількістю ядер, щоб «захиститись на майбутнє», а потім виявляє, що ліцензія базується на ядрі з мінімумом на сокет.
Приходить ревізія фінансів. Раптом «захист на майбутнє» перетворюється на «відкатіться й вибачіться».

Три корпоративні міні‑історії (анонімізовано, болісно правдоподібні)

Міні‑історія 1: Інцидент через неправильне припущення

Середня SaaS‑компанія мігрувала свій API‑фліт з старішого покоління 16‑ядерних машин на нові 32‑ядерні.
Нові машини були дешевші за ядро й мали вищу рекламовану turbo‑частоту. Закупівля була у захваті; SRE‑команда — обережно оптимістична.

За тиждень ротація на он‑колі почала бачити періодичні хвостові стрибки латентності в API, особливо під час сплесків трафіку.
Нічого очевидного: CPU в середньому 40–60%, load average виглядав «нормально», помилок не було — лише повільні запити і розлючені клієнти.

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

Корінною причиною виявився NUMA‑крос‑ток та тиск по пропускній здатності пам’яті. Нові машини мали більше ядер, але іншу конфігурацію каналів пам’яті,
і навантаження — інтенсивний JSON‑парсинг плюс TLS та спільний in‑memory кеш — було чутливим до латентності пам’яті й локальності кешу.
Потоки мігрували між NUMA‑вузлами, перетворюючи кеш‑хіти на віддалені промахи під час сплесків.

Виправлення були нудні й ефективні: прив’язати найгарячіші пула воркерів до NUMA‑вузла, виділити пам’ять локально та обмежити конкурентність відповідно до пропускної здатності пам’яті.
Фліт стабілізувався — але з меншим рівнем «використаних ядер», ніж раніше. Заголовок постмортему був прямим: «Ми купили ядра; нам потрібна була пропускна здатність».

Міні‑історія 2: Оптимізація, що відкотилась

Команда платформи обробки даних запускала розподілений інжест, який стискав payload перед записом у об’єктне сховище.
Вони перейшли з 24‑ядерного CPU на 48‑ядерний «більше ядер за ту ж ціну», очікуючи лінійного масштабування компресії.

Вони зробили те, що роблять хороші інженери: оптимізували. Збільшили рівень стиснення. Зросла паралельність. Підлаштували буфери.
Пропускна здатність у single‑node бенчмарку зросла і зміна була впроваджена.

У продакшні латентність вибухнула, а пропускна здатність впала. Ноди почали накопичувати backpressure, а downstream система почала таймаутитися.
CPU був завантажений, але не в чистому сенсі «виконуємо корисну роботу». Було багато перемикань контексту. Черги виконання довгі. I/O wait дивно підвищився.

Перформанс на ядрі при тривалому всьому‑ядерному навантаженні виявився нижчим через обмеження потужності й інструкційний мікс.
Їхня бібліотека компресії використовувала векторні інструкції, що тригерили зниження частоти. Більше потоків змусило CPU перейти в повільніший стійкий стан.
Гірше: додаткова паралельність породила більше, менших записів і більше метаданих, створивши I/O‑ампліфікацію на шляху сховища.

Вони відкотили оптимізацію, потім повернули її з обмеженнями: менше потоків компресії, консолідовані записи та орієнтир на стабільну all‑core частоту, а не на піковий turbo.
Урок закріпився: масштабування CPU‑зв’язаного етапу може виявити та погіршити I/O‑зв’язане вузьке місце, і «більше ядер» може привести до повільнішої частоти.

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

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

Зйом топології показав два сокети, кілька NUMA‑вузлів на сокет та увімкнений SMT. Базові тести виявили, що навантаження чутливе до
однониткової латентності для деяких запитів і до пропускної здатності пам’яті для аналітики. Воно не було чутливе до сирої кількості потоків.

Перевірка ліцензій показала, що ліцензія БД рахується по фізичному ядрі з мінімумом на сокет і множником залежно від сімейства CPU.
«Більш ядерний сервер» значно збільшив би вартість ліцензій без покращення вирішальних запитів.

Вони обрали інший SKU: менше ядер, вища стійка частота, краща конфігурація пам’яті та передбачувана NUMA‑топологія.
Також налаштували pinning CPU для найгарячіших процесів та перевірили план відтворенням продакшн‑трас.

Під час оновлення нічого драматичного не сталося. Ніяких інцидентів. Ніяких героїчних дій опівночі. Було так тихо, що керівництво майже забуло про це,
що є найвищою похвалою для операційної команди.

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

Мета тут не зібрати тривію. Мета — припинити сперечатися на основі сторінок SKU і почати приймати рішення, ґрунтуючись на машині перед вами.
Кожне завдання містить: команду, приклад виходу, що це означає, і рішення, яке з цього випливає.

Завдання 1: Підтвердити, що ОС вважає «CPU»

cr0x@server:~$ nproc
128

Що це означає: ОС бачить 128 планованих CPU (логічних CPU). Зазвичай це «фізичні ядра × SMT‑потоки», але також може бути обмежено cpuset.

Рішення: Розглядайте це число як площу планування, а не як «128 реальних ядер». Далі — мапувати топологію.

Завдання 2: Перевірити топологію CPU (ядра, потоки, сокети, NUMA)

cr0x@server:~$ lscpu | egrep -i 'Model name|Socket|Core|Thread|NUMA|CPU\(s\)'
CPU(s):                               128
Model name:                           AMD EPYC 7xx3 64-Core Processor
Thread(s) per core:                   2
Core(s) per socket:                   64
Socket(s):                            1
NUMA node(s):                         4

Що це означає: 64 фізичні ядра, SMT=2, один сокет, але чотири NUMA‑вузли (chiplet‑структура). NUMA важлива навіть на одному сокеті.

Рішення: Для latency‑критичних навантажень плануйте NUMA‑pinning і тести локальності пам’яті. Для пропускної здатності — бенчмаркуйте масштабування по NUMA‑вузлах.

Завдання 3: Подивитись, які логічні CPU ділять ядро (SMT‑сіблінги)

cr0x@server:~$ lscpu -e=CPU,CORE,SOCKET,NODE | head
CPU CORE SOCKET NODE
0   0    0      0
1   0    0      0
2   1    0      0
3   1    0      0
4   2    0      0
5   2    0      0
6   3    0      0
7   3    0      0
8   4    0      0

Що це означає: CPU 0 і 1 — два потоки на одному фізичному ядрі, і так далі.

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

Завдання 4: Перевірити поведінку частоти CPU в простої

cr0x@server:~$ sudo apt-get -y install linux-tools-common linux-tools-$(uname -r) >/dev/null 2>&1
cr0x@server:~$ sudo turbostat --Summary --quiet --interval 1 --num_iterations 1
CPU     Avg_MHz   Busy%   Bzy_MHz  TSC_MHz  PkgWatt
-       1420      6.15    3220     3000     68.12

Що це означає: Під легким навантаженням активні ядра підвищують частоту (Bzy_MHz вища за Avg_MHz). Це майже нічого не каже про тривалу all‑core поведінку.

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

Завдання 5: Підтвердити governor CPU і політику енергоспоживання

cr0x@server:~$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
performance

Що це означає: «performance» тримає частоту високою. «powersave» (на деяких системах) може бути прийнятним, але іноді шкодить латентності.

Рішення: Для low‑latency сервісів віддавайте перевагу передбачуваній поведінці частоти. Для батч‑флотів вимірюйте компроміс потужність vs пропускна здатність.

Завдання 6: Швидко виміряти масштабування «по‑ядру» vs «всі‑ядра» (саніті‑тест)

cr0x@server:~$ sudo apt-get -y install sysbench >/dev/null 2>&1
cr0x@server:~$ sysbench cpu --cpu-max-prime=20000 --threads=1 run | egrep 'events per second|total time'
events per second:   381.12
total time:          10.0004s
cr0x@server:~$ sysbench cpu --cpu-max-prime=20000 --threads=64 run | egrep 'events per second|total time'
events per second:   20112.47
total time:          10.0031s

Що це означає: Масштабування тут непогане, але не довіряйте цьому надто: тест compute‑heavy і може не відповідати вашому продакшн‑міксу.

Рішення: Використовуйте це як перевірку «машина не зламана». Для рішень бенчмаркуйте реальне навантаження або відтворення трас.

Завдання 7: Виявити тротлінг CPU через термальне/потужнісне обмеження

cr0x@server:~$ dmesg -T | egrep -i 'throttl|thermal|powercap' | tail -n 5
[Mon Jan 22 10:14:03 2026] intel_rapl_common: Found RAPL domain package
[Mon Jan 22 10:15:41 2026] CPU0: Core temperature above threshold, cpu clock throttled
[Mon Jan 22 10:15:42 2026] CPU0: Core temperature/speed normal

Що це означає: Відбувся тротлінг. Це перетворює «кількість ядер» на красиву історію, а «фактичну продуктивність» — на рухому ціль.

Рішення: Виправте охолодження/повітряний потік, перевірте BIOS‑настройки живлення та повторіть тривалі бенчмарки. Не налаштовуйте софт на термально нестабільній платформі.

Завдання 8: Перевірити 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: 64000 MB
node 0 free: 51000 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
node 1 size: 64000 MB
node 1 free: 12000 MB
node 2 cpus: 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
node 2 size: 64000 MB
node 2 free: 52000 MB
node 3 cpus: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
node 3 size: 64000 MB
node 3 free: 50000 MB

Що це означає: Вузол 1 має мало вільної пам’яті порівняно з іншими. Якщо процес опиниться там, він може виділяти віддалено і платити за латентність.

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

Завдання 9: Перевірити, чи ваш процес страждає від віддалених NUMA‑алокацій

cr0x@server:~$ pidof nginx
2142
cr0x@server:~$ sudo numastat -p 2142 | head -n 8
Per-node process memory usage (in MBs) for PID 2142 (nginx)
        Node 0  Node 1  Node 2  Node 3   Total
Huge       0.0     0.0     0.0     0.0     0.0
Heap     820.4   112.2   640.1    95.7  1668.4
Stack      8.2     1.1     6.3     0.9    16.5
Private  410.5    55.0   320.2    44.7   830.4

Що це означає: Пам’ять розподілена по вузлах; залежно від розміщення CPU деякі доступи будуть віддаленими.

Рішення: Розгляньте запуск однієї групи воркерів на NUMA‑вузел, прив’язки CPU або використання numactl для бинду пам’яті для гарячих процесів.

Завдання 10: Спостерігати навантаження черги виконання та перемикання контексту

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  98124 9234560  0    0     3    17  680 1200 12  3 84  1  0
10  0      0 8119320  98124 9235104  0    0     0     0 2200 9000 55 10 34  1  0
18  1      0 8101000  98124 9238000  0    0     0   420 3500 15000 60 15 20  5  0

Що це означає: r (runnable) високе; cs (context switches) стрибає. Часто це переповнення або конкуренція за блокування, а не «нам потрібно більше ядер».

Рішення: Зменшіть кількість потоків, перевірте блокування, підлаштуйте пули воркерів або зробіть pinning гарячих потоків. Купівля ядер — не перше рішення.

Завдання 11: Підтвердити, що iowait не маскується під обмеження CPU

cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0 (server) 	01/22/2026 	_x86_64_	(128 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          22.10    0.00    6.90   18.40    0.00   52.60

Device            r/s     w/s   rkB/s   wkB/s  await  aqu-sz  %util
nvme0n1         120.0   880.0  7680.0 90240.0  12.4    9.20   96.0

Що це означає: Високе %iowait, висока зайнятість пристрою %util і зростаюча черга (aqu-sz) вказують, що обмежувач — сховище.

Рішення: Не звинувачуйте ядра. Виправляйте сховище: зменшіть write‑ампліфікацію, збільшіть пропускну здатність, додайте кешування або масштабуйте throughput сховища.

Завдання 12: Перевірити розподіл IRQ (класична брехня «CPU високий»)

cr0x@server:~$ cat /proc/interrupts | head -n 8
           CPU0       CPU1       CPU2       CPU3
  24:   9123456          0          0          0   IO-APIC   24-fasteoi   nvme0q0
  25:         0          0          0          0   IO-APIC   25-fasteoi   nvme0q1
  26:         0          0          0          0   IO-APIC   26-fasteoi   nvme0q2
  27:         0          0          0          0   IO-APIC   27-fasteoi   nvme0q3

Що це означає: IRQ накопичуються на CPU0 і створюють штучні гарячі точки та латентність. Пристрій «multi‑queue», але переривання не збалансовані.

Рішення: Увімкніть/перевірте irqbalance, налаштуйте афініті переривань і знову перевірте хвостову латентність перед тим, як міняти кількість ядер.

Завдання 13: Подивитись, чи вас душать cgroups (контейнери)

cr0x@server:~$ cat /sys/fs/cgroup/cpu.stat 2>/dev/null || cat /sys/fs/cgroup/cpu/cpu.stat
usage_usec 932112345
user_usec  701223000
system_usec 230889345
nr_periods  14400
nr_throttled 3920
throttled_usec 412334500

Що це означає: Багато тротлінгу (nr_throttled) і значний час тротлінгу: у вас не «закінчились ядра», у вас закінчилась квота.

Рішення: Збільште CPU‑ліміт, зніміть ліміти для latency‑критичних сервісів або правильно розміркуйте requests/limits і розміри вузлів.

Завдання 14: Порівняти «CPU time» і «wall time», щоб виявити конкуренцію

cr0x@server:~$ /usr/bin/time -v bash -c 'python3 - <

Що це означає: Відсоток CPU близько 100% і wall‑time, що відповідає user‑time, свідчить про чисте виконання на CPU. Якщо wall‑time набагато більший — ви чекаєте, часто на блокування чи I/O.

Рішення: Якщо wall‑time зростає під конкуренцією, розслідуйте конкуренцію перед покупкою більшої кількості ядер.

План швидкої діагностики: як швидко знайти вузьке місце

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

Спочатку: доведіть, які «ядра» у вас насправді

  1. Топологія: lscpu для сокетів/ядер/потоків/NUMA‑вузлів.
  2. NUMA‑тиск пам’яті: numactl --hardware та numastat.
  3. Тротлінг: перевірте dmesg на термальні/потужнісні події; використайте turbostat під репрезентативним навантаженням.

Якщо ви не можете описати свою топологію одним реченням — ви не готові інтерпретувати графіки perf.

По‑друге: визначте, чи це CPU, пам’ять, сховище чи планування

  1. Насичення CPU vs конкуренція: vmstat 1 (черга виконання r, перемикання контексту cs).
  2. I/O wait та насичення пристрою: iostat -xz 1.
  3. IRQ‑гарячі точки: /proc/interrupts та використання черг NIC/NVMe.
  4. Тротлінг cgroup: cpu.stat для часу тротлінгу.

Ціль: класифікувати вузьке місце. «CPU 70%» — це не класифікація.

По‑третє: валідовати одним фокусованим експериментом

  • Прив’яжіть потоки (або тимчасово вимкніть SMT), щоб побачити, чи продуктивність стане передбачуванішою.
  • Змініть конкурентність (наприклад, вдвічі менше воркерів), щоб перевірити, чи пропускна здатність тримається, а латентність поліпшується — класичний підпис конкуренції.
  • Перенесіть навантаження на відоме «хороше» покоління CPU і порівняйте CPU‑час на запит і хвостову латентність.

Один експеримент, одна гіпотеза, один план відкату. Ви робите операції, а не астрологію.

Цитата (перефразована ідея): Ідея John Ousterhout: виміряйте й знайдіть вузьке місце перед оптимізацією — інакше ви просто змінюєте код заради задоволення.

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

Це та частина, яку ви вставляєте в інцидент‑чати, коли люди починають підспівувати «додайте більше ядер».

1) Симптом: «CPU низький, але латентність висока»

  • Корінна причина: тротлінг cgroup, дисбаланс черг виконання або I/O‑зупинки. На вузлі CPU здається простим; ваш pod душать квоти або він чекає на сховище.
  • Виправлення: Перевірте тротлінг у cpu.stat, зніміть CPU‑ліміти для latency‑критичних сервісів і перевірте насичення сховища через iostat.

2) Симптом: «Новий сервер з більшою кількістю ядер повільніший під навантаженням»

  • Корінна причина: нижча стійка all‑core частота, термальне/потужнісне тротлінг або AVX‑індуковане пониження частоти.
  • Виправлення: Виміряйте all‑core частоту за допомогою turbostat під репрезентативним навантаженням; відрегулюйте BIOS‑обмеження потужності і охолодження; за потреби зменшіть паралельність AVX‑важких задач.

3) Симптом: «Масштабування зупиняється на N потоках і потім стає гірше»

  • Корінна причина: конкуренція за блокування, bounce кеш‑ліній, насичення пропускної здатності пам’яті або конкуренція SMT‑сіблінгів.
  • Виправлення: Зменшіть кількість потоків; прив’яжіть до одного потоку на ядро; профілюйте блокування; розділіть роботу по NUMA‑вузлах; розгляньте вимкнення SMT для цього класу навантаження.

4) Симптом: «Великий інстанс повільніший за малий для того ж сервісу»

  • Корінна причина: ефекти NUMA та віддалені алокації пам’яті; трафік між вузлами підвищує хвостову латентність.
  • Виправлення: Біндуйте процеси і пам’ять з урахуванням NUMA; запускайте кілька менших інстансів; або обирайте SKU з меншою кількістю NUMA‑доменів.

5) Симптом: «Одне CPU‑ядро вбитте; інші прості»

  • Корінна причина: афініті переривань/IRQ‑дисбаланс, однониткове вузьке місце або глобальне блокування.
  • Виправлення: Перевірте /proc/interrupts; увімкніть irqbalance; виправте однониткове вузьке місце; шардуйте глобальне блокування; перестаньте думати, що «більше ядер» вирішить послідовну роботу.

6) Симптом: «Ми оновили ядра, тепер сховище стало гіршим»

  • Корінна причина: CPU‑етап розігнався й збільшив I/O‑конкуренцію, виявивши межі черг сховища та write‑ампліфікацію.
  • Виправлення: Лімітуйте швидкість записів, батчуйте/коалесцюйте I/O, налаштуйте queue depth, додайте кешування або масштабуйте пропускну здатність сховища. Розглядайте CPU і сховище як пов’язану систему.

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

Контрольні списки / покроковий план

Чеклист A: Перед тим як купити «більше ядер»

  1. Визначте ціль: пропускна здатність, медіанна латентність, p99 латентність або вартість за запит. Оберіть одну головну метрику.
  2. Зберіть реальні докази вузького місця: черга виконання, iowait, тротлінг і завантаження сховища.
  3. Зніміть топологію: сокети/ядра/потоки/NUMA‑вузли і канали пам’яті (принаймні NUMA‑вузли і вільну пам’ять по вузлах).
  4. Перевірте модель ліцензування: фізичні ядра vs потоки; мінімальні значення на сокет; множники за сімейством CPU.
  5. Бенчмаркуйте реалістично: репрезентативна конкуренція та інструкційний мікс; включайте нагріті кеші; включайте мережу та сховище в ланцюг, коли це важливо.
  6. Визначте «тип ядер» потрібних: висока однониткова продуктивність vs багато ядер; ризик планування гібридних ядер; цінність SMT.

Чеклист B: Коли продуктивність дивна після міграції

  1. Підтвердити відсутність тротлінгу: термальні і потужнісні події в логах; перевірка стійкої частоти.
  2. Перевірити тротлінг cgroup: особливо якщо контейнеризовано; підтвердити, що ліміти не змінились.
  3. Валідовати NUMA‑розміщення: pinning CPU і локальність пам’яті для найгарячіших процесів.
  4. Перевірити баланс переривань: NIC і NVMe‑переривання повинні бути розподілені по CPU.
  5. Порівняти CPU‑час на запит: якщо CPU‑час на запит зріс, ви на повільнішому ядрі або виконуєте більше роботи.
  6. Порівняти латентність сховища: «швидший CPU» може сильніше навантажувати сховище; не плутайте симптоми з причинами.

Чеклист C: Якщо треба пояснити це не‑інженерам

  • Замініть «ядра» на «робота в секунду». Зв’яжіть це з бізнес‑результатом (запити/сек при p99‑цілях).
  • Використайте один графік: пропускна здатність vs латентність при збільшенні конкуренції. Він швидко виявляє конкуренцію і тротлінг.
  • Поясніть NUMA як «відстань до пам’яті». Люди розуміють відстань.
  • Поясніть SMT як «два працівники, що ділять один стіл». Це достатньо точно, щоб уникнути поганих рішень.

FAQ

1) Чи vCPU те саме, що ядра?

Зазвичай ні. vCPU зазвичай відповідає апаратному потоку, а не фізичному ядрі, і його продуктивність залежить від навантаження на хості та покоління CPU.
Розглядайте vCPU‑кількість як квоту планування, а потім вимірюйте реальну пропускну здатність і латентність.

2) Чи слід вимкнути SMT/Hyper‑Threading?

Не вимикайте його з забобону. Тестуйте. Для деяких latency‑критичних або lock‑важких навантажень відключення SMT може покращити хвостову латентність і передбачуваність.
Для throughput‑навантежень SMT може допомагати. Приймайте рішення для кожного навантаження окремо.

3) Чому CPU з більшою кількістю ядер іноді гірший у однонитковій продуктивності?

Бо бюджети дизайну обмежені: потужність, площа кремнію, кеш і частота. CPU, оптимізовані під щільність ядер, можуть мати менший boost,
менші кеші на ядро або нижчі стійкі частоти під навантаженням.

4) Як P‑ядра/E‑ядра впливають на сервери й контейнери?

Гібридні дизайни ускладнюють планування. Без правильної підтримки ядра й політик latency‑чутливі потоки можуть сісти на повільніші ядра.
У контейнерах pinning і CPU‑ліміти можуть посилити помилки планування. Валідовуйте через топологічно‑усвідомлений pinning і виміряну латентність.

5) Який найшвидший спосіб сказати, що я CPU‑bound?

Шукайте високе завантаження і низький iowait, помірні context switches та run queue, що відповідає очікуванням.
Якщо iowait високий або є тротлінг, ви не «CPU‑bound» у сенсі, що купівля додаткових ядер це вирішить.

6) Чому продуктивність погіршується при збільшенні кількості потоків?

Через конкуренцію. Більше потоків підвищують конкуренцію за блокування, bounce кеш‑ліній, накладні на планувальник і тиск на пропускну здатність пам’яті.
Після певної точки машина витрачає час на координацію, а не на виконання корисної роботи.

7) Як NUMA проявляє себе в симптомах?

Типові ознаки: стрибки p99 під сплесками, нерівномірне завантаження CPU по NUMA‑вузлах і деградація продуктивності на «більших» машинах.
Інструменти на кшталт numastat можуть показати віддалені алокації; pinning часто стабілізує поведінку.

8) Чи марні бенчмарки від вендорів?

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

9) Як уникнути сюрпризів з ліцензуванням по ядрам?

Розглядайте ліцензування як первинне технічне обмеження. Перед вибором CPU підтвердіть, що вважають ліцензованим ядром,
чи рахується SMT, чи є мінімуми на сокет і чи застосовуються множники по сімейству CPU.

10) Яка найбільш надійна метрика «кількості ядер» для внутрішнього використання?

Для інженерних дискусій: повідомляйте фізичні ядра, SMT‑потоки та NUMA‑вузли окремо. Для планування ємності: використовуйте «запити/сек при p99‑цілі»
на визначеному апаратному профілі. Це метрика, яка переживе маркетинг.

Висновок: що робити далі

Перестаньте трактувати число в назві CPU як SLA. «Більше ядер» — це можливість, а не гарантія, а іноді ще й бюджетна пастка з радіатором.
Якщо ви підтримуєте продакшн‑системи, ваша задача — перетворити маркетингові іменники на вимірювану реальність.

Практичні наступні кроки:

  1. Знімайте топологію для кожного апаратного профілю: сокети, фізичні ядра, SMT‑потоки, NUMA‑вузли.
  2. Побудуйте невеликий, повторюваний набір бенчмарків: один sanity‑CPU тест, один тест чутливий до пам’яті, один тест зі сховищем у ланцюзі і відтворення трас, якщо можливо.
  3. Для контейнерних платформ регулярно перевіряйте тротлінг cgroup і баланс IRQ перед тим, як «масштабувати вгору».
  4. Купуючи залізо (або інстанси), оптимізуйте під вузьке місце: однониткова латентність, пропускна здатність пам’яті, латентність сховища або вартість ліцензії — а не за кількістю ядер.

Зробіть це — і «64 ядра» знову стане змістовним інженерним вхідним параметром, яким можна користуватись без пробуджень о 3‑й ранку.

← Попередня
Витоки Docker через IPv6: запобігайте випадковому публічному доступу
Наступна →
ZFS zpool initialize: змусити нові диски поводитися краще з першого дня

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