Гонка тактової частоти: чому «більше GHz» перестало працювати

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

Якщо ви коли-небудь купували «швидші» CPU і спостерігали, що затримки в продакшні майже не змінилися, ви вже зіткнулися з кінцем ери GHz.
Дашборди виглядають самовдоволено: CPU менше ніж 40%, load average в нормі, але запити накопичуються, як багаж в аеропорту після снігопаду.

Це сучасна пастка продуктивності: частота перестала бути простим регулятором, а система ускладнилася так, що помилки в припущеннях караються.
Хороша новина — правила можна вивчити. Погана — їх не можна ігнорувати й сподіватися, що turbo boost врятує квартальні показники.

Чому «більше GHz» перестало працювати

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

Стіна потужності: фізика має свою думку

Динамічна потужність у CMOS часто апроксимується як P ≈ C × V² × f.
Можна махнути рукою на константи, але не на квадрати напруги.
Вищі частоти зазвичай вимагають вищої напруги, щоб зберегти часові запаси, і тоді потужність різко зростає.
Потужність перетворюється на тепло, тепло — на тротлінг, а тротлінг перетворює ваш блискучий «4.0 GHz» на практичний «3.1 GHz, якщо вентилятор не переграє».

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

Dennard scaling перестав масштабуватись

Довгий час Dennard scaling робив транзистори меншими, швидшими й енергоефективнішими на одиницю площі.
Орієнтовно в середині 2000-х витік струму та інші ефекти зруйнували цю мрію.
Транзистори продовжували зменшуватися, але припиняли ставати пропорційно «дешевшими» в ватах.
Індустрія не перестала інновувати. Вона просто перестала давати вам безкоштовні пришвидшення для існуючого коду.

Стіна пам’яті: CPU біжить, RAM прогулюється

Навіть якби ви могли крутити частоту, багато серверної продуктивності блокується очікуванням.
Очікування пам’яті. Очікування промахів кеша. Очікування вводу/виводу. Очікування блокувань.
Ядра CPU стали достатньо швидкими, щоб завершувати інструкції героїчно—поки їм не потрібні дані, яких немає в кеші.

Затримки пам’яті покращувалися, але не такими ж темпами, як тактова тривалість CPU. Тому затримка, виміряна в тактах CPU, стала гіршою.
DRAM-доступ, який колись був «трохи повільний», став «вічністю» в циклах ядра.
Сучасні CPU борються з цим більшими кешами, кращими префетчерами, більше out-of-order виконанням і спекулятивними трюками.
Це працює—іноді. Але також ускладнює продуктивність так, що наївна «шопінг по GHz» схожий на купівлю спортивного автомобіля для міського трафіку.

Паралелізм і правильність: інша стіна

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

Операційний переклад такий: апгрейд CPU не провалюється тому, що CPU слабкий. Він провалюється тому, що вузьке місце перемістилось—або ніколи не було CPU.
Якщо ви не вимірюєте, ви оптимізуватимете не те з упевненістю.

Одна цитата, яку варто тримати на стікері:
Парафраз ідеї (Edsger Dijkstra): Якщо ви не можете виміряти це, ви не можете суттєво покращити це.

Жарт №1: Гнатися за GHz у 2026—це як додавати більше кінських сил до авто, що стоїть за трактором—технічно вражає, емоційно — марно.

Цікаві факти та історичний контекст (коротко й по суті)

  • Ранні 2000-ті: Споживчі та серверні CPU активно підвищували частоту; маркетинг концентрувався на GHz, бо це було просто і зрозуміло.
  • Середина 2000-х: Dennard scaling ослаб; зріс витік потужності, і частота стала теплово дорогою, а не «просто інженерною».
  • Урок епохи NetBurst: Деякі дизайни гналися за високими тактами з глибокими конвеєрами; добре на специфікаціях, менше добре в робочих циклах на інструкцію.
  • Мульти-ядра стали мейнстримом: Індустрія переключилась з одноядерної швидкості на мульти-ядерні дизайни як прагматичний витрачач транзисторного бюджету.
  • Ера turbo boost: Чипи почали підвищувати частоту опортуністично в межах теплового/потужного запасу; «base clock» став мінімальною юридичною величиною, а не обіцянкою досвіду.
  • Адаптація Hyper-threading/SMT: Simultaneous multithreading збільшила пропускну здатність, коли виконавчі блоки були недовантажені, але не подвоїла продуктивність і іноді погіршувала хвостову латентність.
  • Кеш став королем: Великі L3 кеші та розумні префетчери стали ключовими конкурентними фішками через вперту затримку пам’яті.
  • NUMA всюди: Багатосокетні та chiplet-дизайни зробили локальність пам’яті проблемою продуктивності, яку можна випадково викликати неправильним планувальником або аллокатором.
  • Бум спеціалізації: Векторні блоки, крипто-розширення, інструкції для стиснення та акселератори (GPU/NPUs) зросли, бо універсальні ядра стикнулись зі зменшенням віддачі.

Що замінило GHz: IPC, кеші, ядра та спеціалізація

IPC: інструкцій за цикл — нова гра престижу

GHz — це як метроном. IPC — це скільки музики ви граєте за такт.
Сучасна продуктивність CPU приблизно продуктивність ≈ частота × IPC, а потім її зменшують затримки: промахи кеша, неправильні передбачення переходів,
бульбашки в конвеєрі та очікування загальних ресурсів.

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

Кеші: продуктивність, якої ви не бачите — поки не втратите

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

Ядра: пропускна здатність, не латентність (якщо вам не пощастить)

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

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

Векторизація та акселератори: спеціалізовані пришвидшення — справжні прирости

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

Планувальник і менеджер потужності: ваш CPU — це результат переговорів, а не абсолют

У 2026 році частота CPU — це політика. Turbo bins, обмеження потужності, тепловий запас, c-states, p-states і планування ядра
визначають, на яких тактах ви фактично працюєте. У щільному датацентрі ідентичні сервери можуть показувати різну продуктивність,
бо їхнє охолодження або подача живлення відрізняються тонко.

Реалії робочих навантажень: куди йде продуктивність

Латентність часто — це ланцюжок дрібних очікувань

Запит не «використовує CPU». Він проходить через черги, блокування, шляхи ядра, NIC-рінги, кеші файлової системи, сховища, буфери баз даних
і код у просторі користувача. Ваш p99 зазвичай не визначається середнім випадком; його визначають найгірші кілька взаємодій:
велика сторінкова затримка, пауза GC, ліміт cgroup через “шумного сусіда”, віддалений NUMA-доступ або збій у сховищі, що тягне потік в uninterruptible sleep.

Використання CPU — брехун, коли CPU чекає

Класична помилка: «CPU 30%, отже резерв є». Не якщо ці 30% — одне гаряче ядро, що завантажено, а решта — простає.
Не якщо у вас багато iowait.
Не якщо є контенція в черзі виконання.
Не якщо ви затримані через пам’ять.

Сховище та мережа: тихі співавтори «продуктивності CPU»

Як інженер зі зберігання, скажу прямо: ви не можете «апгрейдити CPU» щоб вирішити повільні fsync, синхронну реплікацію
або випадково випадково-важкі випадкові читання на невідповідному носії. CPU не виправить хвостову латентність від насиченої черги NVMe, і тим більше
не вирішить RAID-контролер, що тихо відновлює масив.

Аналогічно, проблеми з мережею проявляються як «CPU в порядку, але пропускна здатність упала». Тому що ваші потоки блокуються на сокетах,
ядро відкидає пакети або TLS-рукопотискання застрягають через нестачу ентропії (так, це ще трапляється).

Швидкий план діагностики: знайдіть вузьке місце без тижня зустрічей

По-перше: це час CPU, очікування CPU чи не CPU взагалі?

  1. Перевірте чергу виконання й насиченість CPU: якщо одне або кілька ядер забиті, ви CPU-bound навіть якщо «загальний CPU%» виглядає низьким.
  2. Перевірте iowait і заблоковані задачі: якщо потоки в uninterruptible sleep, ви чекаєте на I/O (сховище або мережеву ФС).
  3. Перевірте тиск пам’яті: великі fault’и і свопінг можуть зробити «швидкий CPU» повільним на практиці.

По-друге: якщо CPU-bound, це пропуск інструкцій чи пам’ятні затримки?

  1. Подивіться на сигнал(и), схожі на IPC: багато циклів з малою кількістю виконаних інструкцій вказує на стаґнацію; високі промахи кеша — звичайний підозрюваний.
  2. Перевірте переключення контексту й контенцію блокувань: багато переключень може означати накладні витрати планувальника або надто велику кількість потоків.
  3. Подивіться стеки процесів: знайдіть, куди йдуть цикли; не гадати.

По-третє: якщо I/O-bound, ідентифікуйте, яка черга заповнюється

  1. Затримка блочного пристрою: велике await/service time або глибокі черги вказують на насичення сховища або проблеми з пристроєм.
  2. Файлова система і writeback: брудні сторінки й тротлінг можуть зупиняти записувачів; fsync-важкі навантаження часті винуватці.
  3. Мережа: ретрансляції, дропи або насичення softirq CPU можуть імітувати «повільні сервери».

По-четверте: перевірте turbo/throttling і політику живлення (бо реальність)

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

Практичні завдання: команди, що означає вивід і яке рішення прийняти

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

Завдання 1: Перевірити реальну поведінку тактової частоти в реальному часі (не маркетингові чисельники)

cr0x@server:~$ lscpu | egrep 'Model name|CPU\(s\)|Thread|Core|Socket|MHz'
Model name:                           Intel(R) Xeon(R) CPU
CPU(s):                               32
Thread(s) per core:                   2
Core(s) per socket:                   8
Socket(s):                            2
CPU MHz:                              1298.742

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

Рішення: Якщо продуктивність погана, підтвердіть активні частоти під навантаженням (Завдання 2) і перевірте governor/обмеження живлення (Завдання 3/4).

Завдання 2: Спостерігайте за частотою по ядрах і навантаженням під час проблеми

cr0x@server:~$ sudo turbostat --quiet --interval 1
     CPU     Avg_MHz   Busy%   Bzy_MHz  TSC_MHz   IRQ  SMI  CPU%c1  CPU%c6  CoreTmp
       -       3120    38.50     4050     2500  12000    0    2.10   40.20      78

Що це означає: Bzy_MHz — ефективна частота при завантаженні; CoreTmp підказує про тепловий запас. Якщо Bzy_MHz нижче очікуваного turbo при високому Busy% і високих температурах — ймовірно, ви обмежені тепловим режимом.

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

Завдання 3: Перевірити governor CPU (поширено в cloud-образах та ноутбуках, пристосованих під сервер)

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

Що це означає: powersave може бути нормальним на сучасних intel_pstate системах, але в деяких конфігураціях воно обмежуватиме відзивчивість.

Рішення: Якщо латентність чутлива, встановіть відповідну політику (часто performance або налаштований профіль) і повторно протестуйте. Не робіть сліпих змін — виміряйте до/після.

Завдання 4: Перевірити індикатори термальних подій і тротлінгу

cr0x@server:~$ sudo dmesg -T | egrep -i 'thrott|thermal|powercap' | tail -n 5
[Mon Jan  8 10:22:11 2026] CPU0: Package temperature above threshold, cpu clock throttled
[Mon Jan  8 10:22:12 2026] CPU0: Core temperature/speed normal

Що це означає: Повідомлення ядра—це ваш тютюновий слід: ваш «GHz» було знижено.

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

Завдання 5: Визначити, чи ви насичені CPU або просто «трохи зайняті»

cr0x@server:~$ uptime
 10:28:44 up 41 days,  3:02,  2 users,  load average: 28.14, 27.90, 26.30

Що це означає: Load average близький або вище числа потоків CPU може вказувати на насичення, але він також рахує задачі в uninterruptible sleep (I/O wait).

Рішення: Поєднайте це з vmstat (Завдання 6), щоб відрізнити тиск на виконувані потоки від блокованого I/O.

Завдання 6: Швидкий огляд черги виконання, переключень контексту й iowait

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
12  0      0 812344  55284 932120    0    0    12    38 8200 9100 55 10 33  2  0
14  0      0 801120  55284 932992    0    0    10    22 8300 9500 58  9 31  2  0
 2  6      0 794224  55284 931880    0    0   120  9800 4100 7000 12  6 40 42  0

Що це означає: r — runnable threads; b — blocked. Високі wa і високий b вказують на I/O-стали. Високий r з низьким id вказує на насичення CPU.

Рішення: Якщо заблоковано/багато I/O — переходьте до завдань по сховищу/мережі. Якщо CPU — профілюйте (Завдання 11/12).

Завдання 7: Визначити, чи одне ядро «прилипло» (брехня «CPU 30%»)

cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0 (server) 	01/09/2026 	_x86_64_	(32 CPU)

01:02:01 PM  CPU   %usr %nice  %sys %iowait  %irq %soft  %steal  %idle
01:02:02 PM  all   18.2  0.0   3.1    0.4    0.0  1.0     0.0   77.3
01:02:02 PM   7   98.5  0.0   1.2    0.0    0.0  0.0     0.0    0.3

Що це означає: CPU 7 завантажений. Загалом виглядає нормально; ваша латентність не дбає про «all».

Рішення: Знайдіть гарячий потік/процес. Розгляньте шардинг, усунення однопотокових вузьких місць або осмислене прив’язування (не случайне).

Завдання 8: Перевірити тиск пам’яті і великі fault’и (комбо «швидкий CPU, повільні page fault’и»)

cr0x@server:~$ sar -B 1 3
Linux 6.5.0 (server) 	01/09/2026 	_x86_64_	(32 CPU)

01:04:11 PM  pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s
01:04:12 PM     12.00     84.00   6200.00      0.00  10200.0     0.00     0.00
01:04:13 PM     18.00   1200.00   7100.00    180.00   9800.0   220.00    60.00

Що це означає: Сплеск majflt/s означає реальні сторінкові помилки з диска. Це руйнує хвостову латентність.

Рішення: Додайте пам’ять, зменшіть робочий набір, налаштуйте кеші або виправте деплой, що роздув використання пам’яті. Не купуйте вищі GHz, щоб «виправити» пейджинг.

Завдання 9: Перевірити NUMA локальність (віддалена пам’ять — «повільний CPU» в масці)

cr0x@server:~$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
node 0 size: 128000 MB
node 0 free:  42000 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
node 1 size: 128000 MB
node 1 free:  18000 MB

Що це означає: Два NUMA-вузли. Нерівномірність вільної пам’яті може підказувати про нерівномірні виділення або pinning.

Рішення: Якщо процес прив’язаний до CPU вузла 1, але виділяє пам’ять в основному на вузлі 0 — очікуйте віддалених читань. Використовуйте numastat (наступне завдання).

Завдання 10: Підтвердити, чи процес платить «податок віддаленої пам’яті»

cr0x@server:~$ pidof myservice
24188
cr0x@server:~$ numastat -p 24188 | head -n 8
Per-node process memory usage (in MBs) for PID 24188 (myservice)
         Node 0      Node 1
Huge         0.00       0.00
Heap     18240.12    1024.55
Stack        8.00       2.00
Private  20110.33    1210.77

Що це означає: Велике виділення на вузлі 0. Якщо планувальник запускає потоки на вузлі 1 — ви виконуєте віддалі читання.

Рішення: Виправте CPU affinity, використайте інтерліювання усвідомлено або запускайте один інстанс на сокет. Часто це дає більше, ніж 200 MHz.

Завдання 11: Визначити топ-споживачів CPU і чи вони в користувацькому чи в ядровому просторі

cr0x@server:~$ top -b -n 1 | head -n 15
top - 13:08:21 up 41 days,  3:42,  2 users,  load average: 28.14, 27.90, 26.30
Tasks: 412 total,   6 running, 406 sleeping,   0 stopped,   0 zombie
%Cpu(s): 61.2 us,  9.7 sy,  0.0 ni, 27.9 id,  0.9 wa,  0.0 hi,  0.3 si,  0.0 st
MiB Mem : 257996.0 total,  92124.3 free,  32110.7 used, 133761.0 buff/cache
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
24188 app       20   0 18.2g   6.1g  120m R  395.0   2.4  123:41.33 myservice

Що це означає: Сервіс використовує ~4 ядра CPU. Системний час—суттєвий; може це мережа, системні виклики, файлова система або контенція.

Рішення: Якщо sy високий — перевірте гарячі точки в ядрі (softirqs, syscalls) і розгляньте offload’и або батчинг. Якщо us високий — профілюйте користувацький код.

Завдання 12: Зразок куди йдуть CPU-цикли (perf top)

cr0x@server:~$ sudo perf top -p 24188
  18.40%  myservice  myservice           [.] parse_json_fast
  11.22%  myservice  myservice           [.] sha256_compress
   7.10%  libc.so.6  libc.so.6            [.] __memmove_avx_unaligned_erms
   4.85%  [kernel]   [kernel]             [k] tcp_recvmsg

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

Рішення: Розгляньте зменшення накладних витрат JSON (бінарний формат, менше полів), увімкніть апаратне прискорення криптооперацій або винесіть хешування в спеціалізовану бібліотеку. Виміряйте вплив на p99.

Завдання 13: Збір підказок з апаратних лічильників (промахи кеша, цикли, інструкції)

cr0x@server:~$ sudo perf stat -p 24188 -e cycles,instructions,cache-references,cache-misses,branches,branch-misses -- sleep 10
 Performance counter stats for process id '24188':

      21,334,112,901      cycles
      15,002,118,777      instructions              #  0.70  insn per cycle
       2,112,440,918      cache-references
         388,004,112      cache-misses              # 18.37% of all cache refs
       3,122,114,662      branches
          61,110,221      branch-misses             #  1.96% of all branches

      10.003022332 seconds time elapsed

Що це означає: IPC ~0.70 вказує на стаґнацію; відносно високий рівень промахів кеша. Ви не «занадто повільні в GHz», ви чекаєте на пам’ять.

Рішення: Сфокусуйтесь на локальності даних: зменшіть pointer-chasing, зменшіть об’єкти, покращіть батчинг або перебудуйте гарячі цикли. Розгляньте більші кеші або меншу кількість потоків, що шкодять кешу.

Завдання 14: Ідентифікувати затримки I/O і глибину черги на блочних пристроях

cr0x@server:~$ iostat -x 1 3
Linux 6.5.0 (server) 	01/09/2026 	_x86_64_	(32 CPU)

Device            r/s     w/s   rKB/s   wKB/s  await  aqu-sz  svctm  %util
nvme0n1         120.0  2100.0   8400  98200   18.40   42.10   0.35  92.0

Що це означає: %util близько 100 і високі await/aqu-sz означають, що черга пристрою глибока й запити чекають. CPU буде виглядати «в порядку», поки застосунок блокується.

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

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

cr0x@server:~$ grep -E 'Dirty|Writeback' /proc/meminfo
Dirty:             1823456 kB
Writeback:          412800 kB

Що це означає: Високі Dirty/Writeback вказують на велику кількість очікуваних очищень. Якщо записувачі тротлінгуються — сплески латентності гарантовано.

Рішення: Перевірте, чи ваш додаток викликає fsync занадто часто, чи потрібні інші опції монтування, або чи варто перемістити логи на окремі пристрої.

Завдання 16: Знайти мережеві ретрансляції і дропи (бо «повільний CPU» іноді — TCP-біль)

cr0x@server:~$ netstat -s | egrep -i 'retransmit|segments retransm|listen|overflow|dropped' | head -n 10
    12345 segments retransmitted
    98 listen queue overflows
    98 listen queue drops

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

Рішення: Налаштуйте backlog, виправте втрату пакетів, масштабуйте фронтенди або відвантажте TLS. Не купуйте вищі такти, щоб компенсувати мережеві дропи.

Жарт №2: Якщо ваше рішення «додати 500 MHz», ви на крок від того, щоб звинуватити ретроградний Меркурій у втраті пакетів.

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

Міні-історія 1: Інцидент через хибне припущення (GHz як доля)

Середня SaaS-компанія мігрувала latency-sensitive API з старих серверів на новіші. Презентація для закупівлі була чистою:
нове покоління, вищий рекламований turbo, більше ядер, «кращий у всьому». Команда очікувала зниження p95.
Натомість p95 погіршився—іноді суттєво—в години піку.

Перша реакція була передбачуваною: звинутити код. Утворився перфоманс «war room», і інженери почали пропонувати мікрооптимізації.
Тим часом SRE помітили дивну річ: найгірша латентність корелювала з підмножиною хостів, і ті хости мали трохи вищі вхідні температури.
Не критично — просто «трохи тепліше».

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

Хибне припущення було не в тому, що «GHz важливі». Хибне припущення було в тому, що «GHz — це константа». У сучасних системах це змінна.
Вони виправили фізичну проблему: покращили потік повітря, перебалансували розташування в шафі і обережно відкоригували power caps в BIOS.
Лише тоді «швидші» CPU стали швидшими, і лише тоді профілювання коду стало сенсовним.

Тривалий урок був операційним: коли продуктивність регресує після оновлення апаратури, розглядайте середовище як першокласного підозрюваного.
Частота — це політика + фізика, а не число, яке ви маєте в кишені.

Міні-історія 2: Оптимізація, що відкотилась назад (більше потоків — менше пропускної здатності)

Команда пайплайна даних мала CPU-важкий enrichment-сервіс. Вони бачили завантаження CPU на 60% і вирішили, що є резерви.
Хтось збільшив пул робочих потоків з 16 до 64. Зміна швидко вийшла, бо «лише конфігурація».
У синтетичних тестах пропускна здатність покращилась. У продакшні ж з’явився жахливий сплеск p99 і загальна пропускна здатність впала в годину пік.

Симптоми були заплутаними: завантаження CPU зросло, але також і переключення контексту. Рівень промахів кеша піднявся.
Сервіс почав таймаутити виклики до даунстрім-залежності, що спричинило ретраї. Ретраї збільшили навантаження, що збільшило таймаути, що збільшило ретраї — класична петля зворотнього зв’язку, підсилена пулом потоків.

Профілювання показало, що гарячі шляхи коду були пам’яттєво-інтенсивні: парсинг, алокації об’єктів, хеш-таблиці та спільний LRU-кеш.
При 64 потоках робочий набір на ядро не вміщувався в кеш, й контенція на блокуваннях спільного кеша зросла.
CPU не був «недовикористаний» на 60%; він уже чекав на пам’ять і конкурував за спільні структури.

Виправлення не було в принципі «менше потоків»; воно полягало в «правильному розмірі конкурентності». Вони зупинились на меншому пулі,
розділили кеші на воркери, щоб зменшити контенцію, і налаштували поведінку аллокатора. Пропускна здатність покращилася, p99 стабілізувався.

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

Міні-історія 3: Нудна, але правильна практика, що врятувала день (базове профілювання і канарки)

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

Новий rollout ядра пішов у пул канарок. Через кілька годин канарки показали трохи вищий системний час і невелике збільшення хвостової латентності.
Нічого драматичного. Саме те, що ви б пропустили, якби дивилися лише середній CPU.
Але базова метрика включала perf stat counters для промахів кеша й переключень контексту, плюс iostat і мережеві ретрансляції.

Дані вказували на зміну поведінки планування і збільшення softirq під навантаженням.
Вони зупинили rollout, відтворили проблему в staging і звузили її до комбінації IRQ-affinity NIC і нового дефолту в енергоменеджменті.
Виправлення було банальним: налаштування IRQ-affinity і застосування tuned-профілю для цього класу навантаження.

Оскільки вони використовували канарки і базові виміри, «інцидент» ніколи не дійшов до клієнтів.
Жодних екстрених ролбеків, жодних звітів керівництву о першій ночі, жодної піци.
Практика була нудною. Але вона була правильною. Так виглядає надійність, коли її роблять свідомо.

Поширені помилки (симптом → корінь → виправлення)

1) Симптом: Загальний CPU низький, але p99 висока

Корінь: Одне ядро завантажене, однопотоковий вузький шлях або серіалізована секція (глобальне блокування, event loop, пауза GC).

Виправлення: Використайте mpstat -P ALL щоб знайти гарячі ядра, потім профілюйте відповідний процес/потік. Зменшіть серіалізацію, шардуйте роботу або винесіть важку роботу з request path.

2) Симптом: «Нові сервери повільніші» в підмножині хостів

Корінь: Тротлінг через тепло, обмеження потужності, різні налаштування BIOS або нерівномірне охолодження.

Виправлення: Підтвердіть ефективні busy MHz за допомогою turbostat, перевірте dmesg на теплові події, уніфікуйте BIOS-профілі і виправте потік повітря/щільність шаф.

3) Симптом: CPU помірний, але пропускна здатність падає під час сплесків записів

Корінь: Насичення черги сховища, fsync-шторм, тротлінг writeback або контенція під час відновлення RAID.

Виправлення: Використайте iostat -x, перевірте Dirty/Writeback, розділіть пристрої для логів, батчуйте fsync або забезпечте IOPS/латентність.

4) Симптом: Більше потоків зробило гірше

Корінь: Контенція, накладні перемикань контексту, трясіння кеша або підсилення даунстріму через ретраї/таймаути.

Виправлення: Виміряйте переключення контексту (vmstat), профілюйте блокування, обмежте конкурентність, розділіть спільні структури і впровадьте backpressure.

5) Симптом: CPU «випадково» стрибає в sys time

Корінь: Насичення softirq в мережі, велика кількість системних викликів, дропи пакетів що викликають ретрансляції, або накладні витрати стеку зберігання.

Виправлення: Перевірте sys% в top, ретрансляції в netstat -s, IRQ-affinity і розгляньте батчинг, offload’и або зменшення системних викликів на запит.

6) Симптом: Латентність погіршується після переходу на мульти-сокетні машини

Корінь: Віддалений NUMA-доступ через розміщення планувальника, дисбаланс у виділенні пам’яті або pinning контейнерів.

Виправлення: Використайте numastat -p, узгодьте CPU і локальність пам’яті (один інстанс на сокет) і уникайте випадкового крос-вузлового трафіку.

7) Симптом: «Прокачав CPU» і не бачимо покращення

Корінь: Вузьке місце в іншому місці: затримка сховища, мережа, блокування в базі даних, пам’ятні стаґнації або серіалізація.

Виправлення: Прогоніть швидкий план діагностики. Доведіть, що CPU — обмежуючий ресурс, перш ніж витрачати гроші або переписувати код.

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

Чекліст A: Перед тим як купувати CPU (або святкувати «вищі GHz»)

  1. Визначте мету: пропускна здатність, p95 латентність, p99 латентність чи вартість на запит. Оберіть одну головну метрику.
  2. Захопіть базову лінію: використання CPU по ядрам, ефективна частота під навантаженням, прикладний рівень промахів кеша, iostat-латентність, мережеві ретрансляції.
  3. Класифікуйте навантаження: обчислювальне, пам’ятне, з блокуваннями, I/O-важке або змішане.
  4. Знайдіть форму масштабування: чи подвоєння інстансів подвоює пропускну здатність? Якщо так — масштабування вшир може обіграти масштабування вгору.
  5. Визначте «хвостові ризики»: паузи GC, fsync, блокування БД, шумні сусіди, тротлінг. Вони домінують в p99.
  6. Обирайте апарат на підставі доказів: більше кеша для пам’яттєвих робіт, стійка потужність для обчислювальних, краще сховище для I/O-важких систем.

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

  1. Підтвердіть тротлінг: turbostat + записи dmesg про теплові події.
  2. Уніфікуйте BIOS і політику живлення: переконайтеся в однакових налаштуваннях по всьому кластеру.
  3. Перевірте NUMA: локальність і прив’язки для великих процесів.
  4. Переконайтесь у паритеті ядра й мікрокоду: несумісності дають заплутані різниці.
  5. Порівняйте perf-лічильники: проксі IPC і рівні промахів кеша; не покладайтеся лише на CPU%.
  6. Лише потім профілюйте код: ви хочете виправляти софт на стабільній апаратній поведінці.

Чекліст C: Покрокова відладка продуктивності в продакшні (досить безпечно)

  1. Почніть із симптомів: p95/p99, рівні помилок, ретраї, довжини черг.
  2. Перевірте насичення: по-ядрове використання CPU, черга виконання, заблоковані задачі.
  3. Перевірте пам’ять: великі fault’и, свопінг, OOM kills, поведінку аллокатора якщо видно.
  4. Перевірте сховище: iostat await/глибина черги; Dirty/writeback якщо багато записів.
  5. Перевірте мережу: ретрансляції/дропи, переповнення listen-черги, softirq CPU.
  6. Коротко профілюйте: perf top або perf stat на 10–30 секунд, а не на годину.
  7. Зробіть одну зміну: відкотіть ризиковані «оптимізації», обмежте конкурентність, відкоригуйте політику, а потім знову виміряйте.

FAQ

1) Якщо GHz не має значення, навіщо CPU все ще його рекламують?

Тому що іноді він має значення, і тому що його легко продавати. Частота все ще впливає на продуктивність, але вона вже не домінуючий важіль
для сучасних навантажень. Стійка продуктивність залежить від обмежень потужності, охолодження, IPC, поведінки кеша і локальності пам’яті.

2) На що дивитись замість GHz при виборі серверів?

Підбирайте апарат під навантаження: розмір кеша і пропускна здатність пам’яті для дано-важких сервісів, стійка потужність і векторні можливості для обчислювальних задач,
та латентність/IOPS сховища для записо-важких систем. Також: топологія NUMA, кількість ядер у порівнянні з ліцензуванням і реальна стійка частота під вашим навантаженням.

3) Чому «загальний CPU%» вводить в оману?

Бо це усереднення по ядрах і приховує прилипання. Одне забите ядро може домінувати над латентністю, поки інші простоять.
Завжди дивіться статистику по ядрах і чергу runnable. Також перевіряйте iowait і заблоковані задачі, щоб відрізнити очікування від роботи.

4) Чи допомагає turbo boost для продакшн-наванттажень?

Може допомогти, особливо для сплесків і одно-потокових піків. Але turbo опортуністичний: він залежить від теплового/потужного запасу.
Під стійким навантаженням багато систем опускаються близько до базової або проміжної частоти. Виміряйте Bzy_MHz під реальним навантаженням.

5) Чи завжди більше ядер краще за вищі такти?

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

6) Чому деякі оптимізації підвищують кількість промахів кеша?

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

7) Як сховище може зробити CPU повільним на вигляд?

Коли потоки блокуються на диску (або мережевому сховищі), CPU простає або чекає, і латентність запиту зростає.
Люди бачать повільні відповіді і думають, що справа в обчисленнях. iostat -x і заблоковані задачі в vmstat зазвичай швидко це виявляють.

8) Який найшвидший спосіб довести, що ви CPU-bound?

Шукайте високу чергу runnable (vmstat r), низький idle, прилипання по ядрах і стабільно низький iowait.
Потім зробіть короткий зразок perf top, щоб підтвердити, що цикли в користувацькому коді, а не в очікуванні на блокування чи I/O.

9) Що таке «dark silicon» і чому це має значення?

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

10) Чи можна «виправити» це обмеженнями контейнера або прив’язкою CPU?

Іноді. Прив’язка може покращити локальність кеша і зменшити джиттер планувальника, але може також створити гарячі точки і NUMA-проблеми.
Ліміти можуть запобігти шумним сусідам, але можуть викликати тротлінг, якщо встановлені занадто низько. Сприймайте їх як хірургічні інструменти: виміряйте до/після.

Висновок: практичні кроки (що робити в понеділок вранці)

Припиніть купувати GHz так, ніби це 2003 рік. Купуйте продуктивність так, як купуєте надійність: підбираючи систему під навантаження і перевіряючи поведінку під реальним навантаженням.
Частота ще частина історії, але вона не є сюжетом.

  1. Прогоніть швидкий план діагностики для вашого сервісу з найгіршою латентністю й класифікуйте вузьке місце: CPU, пам’ятні стаґнації, сховище чи мережа.
  2. Захопіть базову лінію невеликою підмножиною повторюваних команд: по-ядрове використання, ефективні MHz, зразок промахів кеша, iostat-латентність, ретрансляції.
  3. Виправте нудні речі першими: тротлінг, NUMA-локальність, втечі ретраїв і насичення I/O-черг. Це дає драматичні виграші і менше сюрпризів.
  4. Лише потім оптимізуйте код, керуючись профілями. Якщо гарячий шлях — парсинг JSON і хешування, «більше GHz» — це податок; кращі формати й алгоритми — інвестиція.
  5. Робіть зміни продуктивності так, як SRE робить зміни надійності: канарки, плани відкату й вимірювані критерії прийняття.

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

← Попередня
Debian 13: права сокета PHP-FPM — дрібний фікс, що вирішує 502 (випадок №35)
Наступна →
VPN повна сітка для трьох офісів: коли вона потрібна і як її підтримувати керованою

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