3.6.26

Когда процессоры голодают

Автор: Luca Biondi, SQL SERVER. A deep analysis on CPU Starvation

Почему сервер при загрузке ЦП 40% может вести себя как при полностью утилизированных процессорах

Глубокое погружение в справедливость планировщика SOS, сборку мусора Hekaton, сканирование хэш-индексов и почему накопительное обновление CU5 для SQL Server имеет гораздо большее значение, чем думает большинство администраторов баз данных.

В двух словах

  • SQL Server использует кооперативное планирование через планировщик SOS (SOS Scheduler), и рабочие процессы должны добровольно уступать ЦП (yield).
  • Накопительное обновление SQL Server CU5 улучшает справедливость планировщика (scheduler fairness) во время сканирования сборки мусора хэш-индексов в In-Memory OLTP. 
  • Голодание ЦП (CPU starvation) может происходить даже тогда, когда общее использование ЦП выглядит умеренным. 
  • Неправильный размер корзин (bucket sizing) хэш-индексов и длинные цепочки версий могут резко увеличить затраты на обход сборщика мусора. 
  • Постоянный рост runnable_tasks_count часто опаснее, чем процент загрузки ЦП. 

Введение

В этой статье я покажу вам, почему голодание ЦП является одной из самых неправильно понимаемых проблем производительности в SQL Server. Что более важно, вы поймёте, почему накопительное обновление SQL Server CU5 незаметно исправляет потенциально катастрофическую проблему справедливости планировщика внутри сканирования сборки мусора In-Memory OLTP. Голодание ЦП — одна из немногих проблем SQL Server, где среднее использование ЦП может полностью скрыть катастрофическую несправедливость планировщика. Сервер при загрузке ЦП 40% может вести себя как сервер при загрузке ЦП 100%, когда справедливость планировщика разрушается. Многие администраторы баз данных следят только за процентом загрузки ЦП и очень немногие следят за справедливостью планировщика. И именно здесь прячутся одни из самых неприятных проблем производственных систем SQL Server.

Исправление в CU5, касающееся сборки мусора In-Memory OLTP, важно, потому что оно затрагивает самое сердце внутренних механизмов выполнения SQL Server:

  • Планировщик SOS (SOS Scheduler)
  • Кооперативное планирование (cooperative scheduling)
  • Уступка рабочим процессом (worker yielding)
  • Очереди готовых к выполнению задач (runnable queues)
  • Монополизация планировщика (scheduler monopolization)

Что на самом деле означает кооперативное планирование

SQL Server не полагается только на вытесняющее планирование Windows. Внутри SQL Server использует кооперативное планирование через планировщик SOS. Рабочие процессы (workers) должны периодически добровольно уступать ЦП другим процессам в очереди. Если внутренняя задача выполняется слишком долго без уступки, очереди готовых к выполнению задач растут, и другие рабочие процессы испытывают голодание (starvation).

Ключевые концепции, которые должен понимать каждый серьёзный администратор баз данных:

  • SOS Scheduler → внутренняя абстракция планировщика SQL Server
  • Worker → исполнительная единица, назначаемая задачам
  • Quantum → квант времени выполнения
  • Yield → добровольная уступка ЦП
  • Runnable Queue → очередь готовых к выполнению рабочих процессов
  • Scheduler Fairness → сбалансированный доступ к ЦП между рабочими процессами

Проблема начинается, когда некоторые рабочие процессы не уступают достаточно часто.

Почему хэш-индексы могут ухудшить ситуацию

Хэш-индексы In-Memory OLTP чрезвычайно быстры для точечного поиска. Но внутри они полагаются на корзины (buckets) и цепочки хэшей (hash chains). При неблагоприятных условиях эти цепочки становятся дорогими для обхода.

  • Неправильное значение bucket_count
  • Интенсивные рабочие нагрузки по удалению
  • Неравномерное распределение ключей (skewed key distribution)
  • Высокий уровень коллизий
  • Большое количество изменений версий строк

Большие хэш-цепочки увеличивают затраты на обход при сборке мусора. При высокой нагрузке на изменения рабочие процессы сборки мусора могут тратить чрезмерное время на сканирование цепочек версий и хэш-корзин. Именно здесь начинается монополизация планировщика.

Внутренности сборки мусора (Garbage Collection)

Здесь под капотом становится очень интересно. In-Memory OLTP использует:

  • Версионирование строк (row versioning)
  • Видимость по временным меткам (timestamp visibility)
  • Цепочки версий (version chains)
  • Сборку мусора на основе эпох (epoch-based garbage collection)
  • Резидентность в памяти (memory residency)

In-Memory OLTP не удаляет удалённые строки немедленно. Старые версии строк остаются видимыми для активных транзакций до тех пор, пока продвижение эпохи (epoch advancement) не позволит сборщику мусора выполнить очистку. Это означает, что сборка мусора не является опциональной. Это архитектурное требование со времён появления Hekaton. И при интенсивных рабочих нагрузках сборка мусора может стать чрезвычайно требовательной к ЦП.

Диагностика

Начните с проверки давления на планировщик.

-- Диагностический запрос давления на планировщик SELECT scheduler_id, cpu_id, current_tasks_count, runnable_tasks_count, active_workers_count, pending_disk_io_count, load_factor FROM sys.dm_os_schedulers WHERE status = 'VISIBLE ONLINE';

Постоянное значение runnable_tasks_count больше нуля подозрительно. Особенно в системах, использующих нагрузки Hekaton.

Запрос

Теперь проверьте ожидания типа SOS_SCHEDULER_YIELD.

-- Основные ожидания планировщика SELECT wait_type, waiting_tasks_count, wait_time_ms FROM sys.dm_os_wait_stats WHERE wait_type = 'SOS_SCHEDULER_YIELD';

Важно:

  • Здоровая уступка (yielding) — это НОРМАЛЬНО
  • SOS_SCHEDULER_YIELD сам по себе НЕ является автоматически плохим
  • Рост очереди готовых к выполнению задач — это реальный сигнал опасности

Проблема появляется, когда рабочие процессы не уступают справедливо, а очереди готовых к выполнению задач продолжают расти.

Статистика хэш-индексов (ЭТО DMV — ЗОЛОТО)

-- Статистика хэш-индексов SELECT OBJECT_NAME(object_id) AS table_name, name, total_bucket_count, empty_bucket_count, avg_chain_length, max_chain_length FROM sys.dm_db_xtp_hash_index_stats;

Это динамическое административное представление может выявить:

  • Неправильный размер корзин
  • Чрезмерные коллизии
  • Длинные цепочки обхода
  • Потенциальное увеличение затрат на обход сборщика мусора

Насыщение ЦП против голодания ЦП

Насыщение ЦП
(CPU Saturation)
Голодание ЦП
(CPU Starvation)
Что происходитЦП действительно заполненРазрушение справедливости планировщика
ПричинаВысокая стоимость ЦП запросовМонополизация рабочим процессом
Ключевой факторДавление параллелизмаДисбаланс уступки (yield imbalance)
Характер системыСистема занятаСистема несправедлива

Реальные симптомы, которые администраторы баз данных действительно видят

  • ЦП не на 100%, но система чрезвычайно медленна
  • Случайные всплески задержки
  • Задержки при входе в систему
  • Задержки синхронизации группы доступности (AG)
  • Ожидания типа THREADPOOL
  • Тайм-ауты запросов
  • Всплески очереди готовых к выполнению задач
  • Периодические зависания (intermittent stalls)

Многие администраторы баз данных ошибочно диагностируют эти проблемы как общие проблемы ЦП. В реальности проблема может заключаться в разрушении справедливости планировщика.

NUMA и дисбаланс планировщика

Голодание часто влияет не на все планировщики одинаково. Это становится особенно заметно на:

  • NUMA-системах
  • Средах Soft-NUMA
  • Серверах с большим количеством ядер

Некоторые планировщики могут стать «горячими», в то время как другие остаются недогруженными.

Это создаёт:

  • Неравномерное распределение рабочих процессов
  • Локализованное давление на планировщик
  • Искусственные всплески задержки

Моя работающая стратегия

В реальных производственных системах я НИКОГДА не оцениваю только сырой процент загрузки ЦП. Я анализирую вместе (correlate):

  • Ожидания SOS_SCHEDULER_YIELD
  • Рост очереди готовых к выполнению задач
  • Ожидания THREADPOOL
  • Интенсивность нагрузки Hekaton
  • Статистику цепочек хэш-индексов
  • Дисбаланс NUMA
  • Всплески задержки

Если очереди готовых к выполнению задач остаются высокими в течение продолжительных периодов, я немедленно подозреваю несправедливость планировщика.

Мои рекомендации:

  • Установите CU5, если вы активно используете In-Memory OLTP
  • Непрерывно отслеживайте runnable_tasks_count
  • Проверьте размер корзин хэш-индексов
  • Избегайте чрезмерно больших конфигураций bucket_count
  • Отслеживайте рост цепочек версий
  • Следите за дисбалансом планировщиков между узлами NUMA

Вывод

SQL Server CU5 — это не «очередное накопительное обновление». Оно напрямую улучшает справедливость планировщика в одной из наиболее чувствительных к ЦП областей движка SQL Server.

Для систем, чувствительных к задержкам, таких как:

  • Торговые платформы
  • Приёма данных телеметрии
  • Каналы IoT
  • API реального времени
  • Бэкенды микросервисов

Даже небольшие всплески голодания могут уничтожить 99-й перцентиль задержки (P99 latency). И именно поэтому понимание внутренних механизмов планировщика SOS больше не является опциональным для серьёзного устранения проблем производительности SQL Server.

Официальные источники






Комментариев нет:

Отправить комментарий