Что такое 50% cpu?
- четверг, 31 октября 2024 г. в 00:00:10
Если у вас на машине стрелочка показывает, что у вас осталась половина бака, то у вас точно осталась половина бака? На самом деле больше, так как современные машины врут и топлива еще немного есть, даже когда стрелка на нуле - забота об альтернативно одаренных водителях. А если сервер показывает 50% cpu, то сколько ресурсов у нас осталось?
Для многих ответ ясен, и это не 50%. Поэтому извините, если многие вещи будут вам очевидны. А вот для менеджеров, например, которые планируют ресурсы, это может быть открытием.
Сразу скажу, что эффект ярче проявляется на больших серверах - монстрах с 256 - 1 - 2Tb RAM и 40-48 cpu и более. На маленьком домашнем компе и питоновском скрипте в один тред вы его точно не прочувствуете. Как о примере больших серверов мы будем говорить о серверах баз данных (остальные сервера легко шардить), в частности, о MS SQL
Итак, когда сервер сильно нагружен (cpu > 50%), то многие процессы работают медленнее. Вы хотите сказать, cпасибо, кэп? Не торопитесь. Прикол не в том, что они работают медленее в секундах - это было бы понятно, ожидание диска, ожидание cpu. Прикол в том, что процессы начинают жрать больше cpu! Вот так, самым натуральным образом!
Здесь проявляются два эффекта. Первый связан с паразитным потреблением cpu. Например, часть latch waits в MS SQL являются нормальными ожиданиями (например ожидание диска, PAGEIOLATCH), часть же более 'быстрых' latches являются классческими spin locks, например, PAGELATCH. При конфликтах по страницам все больше cpu создается этими spin locks.
Чем больше spin locks, тем больше cpu, тем медленнее вставки, тем больше spin locks! Здравствуй, положительная обратная связь и metastable failure state ! Впрочем, и без PAGELATCH мы можем перегрузить scheduler, в котором есть и spin locks и вызов getTimePrecise со сменой контекста и переходом в ядро ОС, о таких эффектах я писал тут.
Впрочем, скриншот со временем выше получен от выполнения natively compiled функции, которая проверяет число на простоту. Там нет ни вызова scheduler после каждой строки (проклятия обычного кода на T-SQL), ни IO, ничего кроме, собственно, вычислений. Почему же она стала потреблять больше CPU?
Вспомним про кеши процессора разных уровней. Вспомним про то, как изменение порядка обхода двумерного массива [x,y] (по какой переменной внешний цикл) может ускорить или замедлить выполнение в разы. Собственно, MS SQL это кошмар для системы кеширования - работает сервер с терабайтом ОЗУ, и даже если горячее множество buffer pool 10% от общего объема, то есть 100Gb во много раз превышает все кеши, часть из которых еще и дробятся между многими ядрами. А если взять DWH/reporting server, который реально этот теребайт сканирует full scanом, то вообще туши свет...
Жаль что параметры memory cache misses можно измерить только специальным оборудованием с платы, но я уверен, что базы данных - самые ужасные программы с точки зрения cache misses (может кто-нибудь умеет измерять такие вещи?)
Я также уверен что cross NUMA memory channel на DB серверах перегружен - да, MS SQL сервер "NUMA aware", то есть строит политики переключения threads с учетом NUMA, но вот BUFFER POOL вещь общая и рандомная, и если нужная страница уже в памяти, то в твоей памяти или в памяти другого NUMA - это как повезет (и, кстати, с учетом скорости современных NVMe - не быстрее ли прочитать такую страницу с диска а не с соседнего NUMA? Честно, не знаю)
Но что еще? О чем мы думаем, когда видим очень много cpu cores? Да, конечно о hyperthreading. И втором конвейере, который дает некоторый прирост производительности, но это совсем не то, что "честный" второй процессор. Поэтому, на hyperthreaded серверах "вторые" 50% cpu - это чистый обман (но "в партии не дураки сидят" (c), системы естественно пытаются вначале использовать настоящие ядра).
Я провел эксперимент - программа вычисления простого числа запускалась на сервере, и потом я собрал статистику за долгое время:
Очевидна деградция производительности при высоком CPU, хотя лично я ожидал более резкого перегиба графика в районе 50%. Ну это можно исправить, chatGPT, сгенери мне набор данных где резкая деградация начинается... Ладно, ладно, поступим как ученый старой школы и запостим что есть.
В среднем деградация составляет 60%, но в моменте бывает до трех раз (и снова встречаем положительную обратную связь).
Кстати, при высоком CPU MS SQL server пугается и делает вот так:
и выключает QueryStore (переводит в read only режим). Далее могут наблюдаться проблемы с sp_whoisactive и если все совсем плохо, то даже с тривиальным select * from sysprocesses
В итоге имеем: