← Назад к вопросам

Что такое CPU steal-time?

3.0 Senior🔥 112 комментариев
#Observability#Операционные системы и Linux

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое CPU Steal-Time?

CPU steal-time — это метрика, которая показывает, сколько процессорного времени виртуальная машина (ВМ) ожидала, но не получила от физического гипервизора, потому что тот был занят обслуживанием других виртуальных машин или своих собственных задач. Это ключевой показатель в виртуализированных средах, который помогает оценить «конкуренцию» за ресурсы CPU на гипервизоре.

Как работает CPU Steal-Time: технические детали

В виртуализированной инфраструктуре (например, на базе KVM, Xen, VMware или облачных платформ вроде AWS EC2, Google Cloud) гипервизор управляет распределением физических ресурсов CPU между гостевыми ВМ. Каждая ВМ получает виртуальные CPU (vCPU), которые мапятся на физические ядра или их часть.

Когда ВМ готова выполнять код, она ожидает, пока гипервизор выделит ей реальное процессорное время. Если гипервизор перегружен (например, на хосте запущено слишком много ВМ), ВМ может оказаться в состоянии «готовности, но не запущенной». Время, проведённое в этом состоянии, и фиксируется как steal-time.

С точки зрения ОС внутри ВМ, steal-time измеряется через счётчики процессора. В Linux, например, эти данные доступны в /proc/stat в строке cpu:

# Пример вывода /proc/stat
cpu  1000 0 500 3000 0 200 0 0 0 0
# Поля: user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice

Здесь steal — это время в тиках (обычно 1/100 секунды), которое ВМ ожидала CPU. Его также можно получить через утилиты вроде top, vmstat или mpstat:

# Показать steal-time через mpstat
mpstat 1 5
# Пример вывода:
# 05:30:00 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
# 05:30:01 PM  all   12.50    0.00    3.75    0.00    0.00    0.25    5.00    0.00    0.00   78.50

Почему steal-time важен для разработчика на Go?

  1. Диагностика производительности приложений: Высокий steal-time (например, >5-10% постоянно) может быть причиной необъяснимых латентностей или просадок в throughput вашего Go-приложения, даже если код оптимизирован. Горутины могут «простаивать» не из-за блокировок в коде, а из-за нехватки CPU на гипервизоре.

  2. Масштабирование и планирование ресурсов: В микросервисной архитектуре на основе контейнеров (Docker, Kubernetes), работающих на виртуальных машинах, steal-time помогает определить, является ли проблема недостатком ресурсов на ноде. Например, если вы видите растущий steal-time вместе с увеличением latency, возможно, нужно уменьшить количество подов на ноде или перейти на инстансы с гарантированным CPU.

  3. Настройка пулов воркеров и горутин: В Go вы можете столкнуться с ситуацией, когда runtime.NumGoroutine() показывает много работающих горутин, но приложение медленное. Анализ steal-time (через мониторинг) может указать, что проблема в инфраструктуре, а не в коде. Это помогает избежать преждевременной оптимизации логики приложения.

Как интерпретировать значения steal-time?

  • 0-3%: Норма, конкуренция за CPU минимальна.
  • 3-10%: Умеренная конкуренция. Стоит наблюдать за трендом.
  • >10%: Высокая конкуренция. Производительность приложения, особенно CPU-bound (например, обработка данных, шифрование), может значительно снижаться.
  • Резкие скачки: Могут указывать на «шумных соседей» на том же физическом хосте (например, ВМ с высокой нагрузкой).

Практический пример на Go

Допустим, у вас есть CPU-bound задача — вычисление чисел Фибоначчи. Вы запускаете её в горутинах на виртуальной машине с высоким steal-time:

package main

import (
    "fmt"
    "runtime"
    "time"
)

func fib(n int) int {
    if n < 2 {
        return n
    }
    return fib(n-1) + fib(n-2)
}

func main() {
    start := time.Now()
    numCPU := runtime.NumCPU()
    results := make(chan int, numCPU)

    // Запускаем горутины по числу vCPU
    for i := 0; i < numCPU; i++ {
        go func() {
            results <- fib(40) // Тяжёлое вычисление
        }()
    }

    // Собираем результаты
    for i := 0; i < numCPU; i++ {
        <-results
    }

    elapsed := time.Since(start)
    fmt.Printf("Выполнение заняло %v\n", elapsed)
}

При низком steal-time выполнение займёт, скажем, 10 секунд. При высоком steal-time (например, 20%) — может увеличиться до 12-15 секунд, потому что ОС внутри ВМ не может выделить горутинам достаточно CPU-квантов.

Как минимизировать влияние steal-time?

  • Мониторинг: Внедрите сбор метрик steal-time (через Prometheus, Datadog или облачные мониторинги). Для Go-приложений можно экспортировать системные метрики через github.com/prometheus/node_exporter.
  • Выбор инстансов: В облаках используйте инстансы с гарантированным CPU (например, AWS C5 с фиксированной тактовой частотой, а не T3 с burst).
  • Вертикальное масштабирование: Увеличьте vCPU для ВМ, если гипервизор позволяет.
  • Горизонтальное масштабирование: Распределите нагрузку на большее число ВМ с меньшим количеством vCPU каждая.
  • Диалог с провайдером: В публичных облаках при стабильно высоком steal-time можно обратиться в поддержку с запросом на миграцию на менее загруженный хост.

Заключение

CPU steal-time — это не просто «системная метрика», а важный источник информации для разработчика на Go, особенно при работе в облаках. Она помогает отделить проблемы инфраструктуры от проблем кода, корректно планировать ресурсы и обеспечивать стабильную производительность приложений. Игнорирование steal-time может привести к долгим и бесплодным попыткам оптимизации уже эффективного кода, в то время как реальная проблема — в гипервизоре.