Clocksource TSC unstable — Решение рассинхронизации таймеров в Linux
Архитектура ошибки и симптомы сбоя
Сообщение «clocksource: timekeeping watchdog: Marking Clocksource TSC as unstable» регистрируется подсистемой ядра Timekeeping / Clocksource Watchdog. Ошибка означает, что сторожевой таймер ядра (обычно HPET или ACPI PM Timer) зафиксировал расхождение (Clock Drift) между аппаратными счетчиками тактов TSC (Time Stamp Counter) на разных ядрах или сокетах процессора. Ядро объявляет таймер TSC нестабильным и принудительно переключается (Fall back) на более медленный источник времени (HPET / acpi_pm), что приводит к резкому росту накладных расходов системных вызовов gettimeofday() (падение производительности до 30%).
Диагностическая таблица параметров сбоя
| Параметр | Значение | Инженерный смысл сбоя |
|---|---|---|
| TSC (Time Stamp Counter) | Fast Hardware Register | Сверхбыстрый счетчик тактов CPU; считывается за несколько наносекунд без системного вызова (vDSO). |
| Clocksource Fallback | hpet / acpi_pm | Медленные внешние таймеры системной платы; требуют тяжелых системных вызовов в ядро. |
| TSC Drift Cause | C-States / Numactl / VM Drift | Переходы процессора в глубокие режимы сна C-States, плавающая частота CPU или паузы гипервизора. |
Пошаговое дерево решений и сценарии траблшутинга
Сценарий 1: Проверка доступных и текущих источников времени
# Просмотр доступных источников времени в системе:
cat /sys/devices/system/clocksource/clocksource0/available_clocksource
# Просмотр текущего активного источника времени:
cat /sys/devices/system/clocksource/clocksource0/current_clocksourceЕсли вместо tsc или kvm-clock активен hpet или acpi_pm, сервер теряет производительность.
Сценарий 2: Принудительное включение надежного TSC в параметрах GRUB
Если процессор аппаратно поддерживает инвариантный TSC (Invariant/Constant TSC):
# Добавьте в /etc/default/grub параметры надежного TSC и отключения глубоких C-States:
GRUB_CMDLINE_LINUX="tsc=reliable clocksource=tsc processor.max_cstate=1 idle=poll"
# Обновите конфигурацию GRUB:
sudo update-grub
sudo rebootСценарий 3: Настройка источника времени для виртуальных машин KVM/QEMU
Внутри виртуальных машин лучшим источником времени является паравиртуальный таймер kvm-clock:
# Принудительная установка kvm-clock для виртуальной машины Linux:
echo kvm-clock | sudo tee /sys/devices/system/clocksource/clocksource0/current_clocksource
# Проверка флагов процессора хоста:
cat /proc/cpuinfo | grep -m 1 -E "(constant_tsc|nonstop_tsc)"Сценарий 4: Настройка службы синхронизации Chrony (PTP / NTP)
# Установка Chrony для компенсации системного дрейфа времени:
sudo apt-get install chrony || sudo dnf install chrony
# Проверка статуса синхронизации и дрейфа частоты:
chronyc trackingITSTM выполнит оптимизацию таймкипинга Linux-ядра, настройку vDSO, синхронизацию высокоточных PTP-таймеров и тюнинг C-States.
Частые вопросы (FAQ)
Почему переключение с TSC на HPET так сильно снижает производительность СУБД?
Счетчик TSC читается процессором напрямую через vDSO в пространстве пользователя за 10-15 наносекунд без переключения контекста. Чтение таймера HPET требует полноценного системного вызова и чтения регистров через системную шину (MMIO), что занимает сотни наносекунд и создает колоссальный оверхед при миллионах запросов gettimeofday/clock_gettime в секунду.
Что означают флаги constant_tsc и nonstop_tsc в /proc/cpuinfo?
constant_tsc означает, что счетчик тикает с постоянной частотой независимо от текущего P-state (множителя) процессора. nonstop_tsc означает, что счетчик не останавливается даже при переходе ядра в энергосберегающие состояния глубокого сна C-States.
Почему TSC часто помечается как unstable на многосокетных серверах (NUMA)?
На двух- и четырехсокетных материнских платах генераторы тактовых частот разных процессоров могут иметь минимальный температурный дрейф относительно друг друга. При миграции потока с CPU 0 на CPU 1 ядро замечает сдвиг времени назад/вперед и отключает TSC.
Как переключить clocksource обратно на tsc без перезагрузки сервера?
Выполните команду: echo tsc | sudo tee /sys/devices/system/clocksource/clocksource0/current_clocksource (если ядро не заблокировало TSC полностью).