Облачный сервер для production: как оценить CPU steal, диск и сеть
У двух провайдеров могут быть одинаковые характеристики: 4 vCPU, 8 GB RAM, 100 GB SSD, гигабитный канал. При этом цена отличается на 15%, и разница неочевидна. Но через неделю нагрузочных тестов выясняется: p99-задержки у серверов расходятся в разы.
Облачный сервер с «бумажными» характеристиками это то, что провайдер выделил виртуально. Что происходит в железе, остаётся отдельным вопросом. Когда сосед по гипервизору кладёт что-то тяжёлое, дисковая очередь растёт или канал режут по полосе, ничего из этого в спецификации тарифа нет.
Чтобы не обнаружить проблему уже в продакшене, стоит прогнать три блока тестов до миграции: CPU steal, дисковая подсистема и сеть. Инструменты стандартные: vmstat, fio, iperf3. Интерпретировать результаты нужно в контексте нагрузки, тарифа и времени измерения.
Почему синтетических бенчмарков недостаточно
Geekbench, sysbench, UnixBench замеряют потолок: максимум, который сервер может показать в коротком тесте. Продакшен так не работает. Нагрузка нестабильна, а соседи по физическому узлу непредсказуемы.
В облаке ресурсы виртуальные, и провайдеры применяют оверкоммит: виртуальных ядер на узле выделяется больше, чем можно гарантировать физически при одновременной нагрузке. Пока суммарная нагрузка умеренная – всё в порядке. Когда несколько VM одновременно дают всплески, растёт steal time и дисковая очередь, сеть упирается в лимиты или шейпинг. Это и есть эффект «шумных соседей». Он проявляется непредсказуемо, потому что зависит от того, кто ещё размещён на вашей физической ноде прямо сейчас.
Короткие синтетические тесты не всегда это показывают: они выполняются на общей ноде, но могут не попасть в периоды конкуренции с другими VM за ресурсы. Реальное тестирование облачного сервера должно включать не только короткие синтетические тесты, но и наблюдение за поведением системы в динамике. Для первичной проверки обычно достаточно 30–60 минут нагрузки, а более длительный мониторинг в течение 24–72 часов помогает выявить периодические проблемы с конкуренцией за ресурсы.
Три вещи остаются за кадром при коротком синтетическом тесте. Первое – эффект соседей: ваша VM не одна на физической машине. Второе – нелинейность дисков: SSD ведёт себя по-разному при чистом чтении, чистой записи и их смеси. Третье – временные эффекты сети: burst-лимиты, суточные паттерны шейпинга, перестройка BGP-маршрутов при переключении аплинков.
CPU steal: как увидеть ожидание CPU на гипервизоре
CPU steal time – это процент времени, когда ваш vCPU готов к работе, но гипервизор не предоставляет ему физическое ядро. Причиной может быть высокая загрузка хоста, конкуренция с другими VM, особенности планировщика или условия конкретного тарифа. Для приложения это будет дополнительной задержкой без видимой причины – процессор загружен, а работу не выполняет.
Следить за CPU steal time удобнее всего в реальном времени. В выводе vmstat правая группа колонок – блок cpu: us – user, sy – system, id – idle, wa – ожидание диска, st – steal. Если st держится выше нуля несколько строк подряд, нужно смотреть динамику, а не разовый всплеск:
vmstat 1 30
Статистику за длинный период удобно собирать через sar. Запускать стоит дважды: в покое и под нагрузкой. Разница между срезами покажет, как ведёт себя steal при конкуренции:
sar -u 1 300
Можно посмотреть показатели по каждому vCPU отдельно, чтобы убедиться, нет ли концентрации steal на отдельных vCPU. Такая картина может указывать на особенности планирования или размещения VM:
mpstat -P ALL 1 10
Если вы используете Prometheus, node_exporter экспортирует node_cpu_seconds_total с меткой mode="steal". Так удобно смотреть изменение steal во времени, а не отдельные срезы в терминале.
Практические ориентиры по значениям steal:
<1% - Обычно не вызывает проблем
1–5% Стоит наблюдать в динамике, особенно при чувствительной нагрузке
5–10% Может влиять на хвостовые задержки
>10% Повод обратиться в поддержку и проверить ноду, тариф или инфраструктуру провайдера
Как интерпретировать steal в разных сценариях
Для CPU-bound задач (транскодирования, ML-инференса, компиляции) steal транслируется напрямую во время выполнения. Steal 5% может означать близкую по масштабу потерю доступного CPU-времени, а также нерегулярные паузы от гипервизора, которые нарушают предсказуемость.
Для latency-sensitive API – REST, gRPC, запросов к базам данных – зависимость нелинейная. Медиана может держаться в норме, а p99 растёт: в моменты роста steal запросы накапливаются в очереди. Производительность облачного сервера при steal выше 3–5% для таких сервисов стоит проверять под реальной нагрузкой, синтетический тест этого поведения не показывает.
Отдельный случай – кратковременные всплески steal до 15–20% на несколько секунд при нормальных фоновых показателях. Так бывает при «пробуждении» нагруженной VM на соседнем слоте. Для realtime-сервисов такие пики особенно опасны: даже 3-секундный скачок latency может спровоцировать каскадные таймауты ниже по стеку.
Если steal растёт в определённые часы суток, это может указывать на регулярную конкуренцию за ресурсы или особенности нагрузки на хост. Паттерн удобно поймать через запись в файл:
sar -u 1 3600 > cpu_hour.log
Сравните значения st в разные промежутки. При устойчивом росте в пиковые часы стоит обратиться в поддержку и проверить, связана ли проблема с конкретной нодой, тарифом или инфраструктурой провайдера.
Диск: IOPS, latency и поведение под смешанной нагрузкой
нагрузкой
Многие провайдеры публикуют либо максимальные IOPS в идеальных условиях, либо ничего конкретного. В обоих случаях цифра мало что говорит о реальном поведении под смешанной нагрузкой.
В выводе iostat важны два параметра. await – среднее время выполнения запроса к диску в миллисекундах, включая ожидание в очереди. avgqu-sz – средняя глубина очереди: когда она растёт, await растёт следом. В новых версиях sysstat await разделён на r_await и w_await – лучше смотреть оба.
Мониторинг дисковой подсистемы запускайте параллельно с нагрузочным тестом:
iostat -xz 1 10
Для нагрузочного теста используется fio. Крайне важен флаг --direct=1: без него тест уходит в страничный кеш Linux и не отражает поведение диска. Параметры numjobs и iodepth задают глубину очереди: в примере с numjobs=4 и iodepth=32 суммарная глубина очереди равна 128, что перекрывает большинство всплесков при конкуренции потоков. В выводе смотрите на iops и clat p99: этот показатель помогает оценить вклад диска в хвостовые задержки запросов. В примерах ниже используется ioengine=libaio, но для современных Linux-конфигураций также можно рассматривать io_uring, если он поддерживается системой и версией fio.
Случайное чтение 4K – типичная OLTP-нагрузка:
fio --name=rand4k_read --rw=randread --bs=4k --direct=1 \
--numjobs=4 --iodepth=32 --size=4G --runtime=60 \
--time_based --ioengine=libaio --group_reporting
Последовательная запись 1 MB – журналы, бэкапы, дамп БД:
fio --name=seq_write --rw=write --bs=1M --direct=1 \
--numjobs=1 --iodepth=4 --size=10G --runtime=60 \
--time_based --ioengine=libaio
Смешанная нагрузка 70/30 – реалистичная модель для большинства веб-приложений:
fio --name=mixed --rw=randrw --rwmixread=70 --bs=4k --direct=1 \
--numjobs=4 --iodepth=32 --size=4G --runtime=60 \
--time_based --ioengine=libaio --group_reporting
Ориентиры для БД и веб-приложений
Нет единого числа IOPS, которое подходит всем: зависит от характера нагрузки, размера рабочего набора и активности кеша. Примерные ориентиры для тестирования облачного сервера под разные типы нагрузок:
PostgreSQL / MySQL, средняя — 4K rand IOPS: ≥5 000; await: <2 мс; %util: <70%
PostgreSQL / MySQL, высокая — 4K rand IOPS: ≥20 000; await: <1 мс; %util: <70%
Redis (с AOF) — 4K rand IOPS: ≥10 000; await: <1 мс; %util: <60%
Nginx / файловый сервис — 4K rand IOPS: ≥1 000; await: <5 мс; %util: <80%
Эти значения не универсальны: реальные пороги зависят от типа хранилища, профиля нагрузки, размера рабочего набора, кеша и требований конкретного приложения.
Если avgqu-sz устойчиво держится выше 8–10 под OLTP-нагрузкой, это первый признак насыщения: запросы встают в очередь, потому что диск не успевает. %util близко к 100% само по себе не катастрофа для SSD, но если при этом растёт await – диск работает на пределе.
Для облачных блочных устройств с гарантированными IOPS пороги обычно срабатывают раньше, чем %util достигнет 100%: провайдер режет I/O на установленном лимите, и очередь начинает расти задолго до насыщения железа. Именно await покажет это первым.
Тестировать стоит с той же глубиной очереди, что предполагается в продакшене: для PostgreSQL это обычно 8–32, для Redis – ниже.
Сеть: полоса, PPS, latency и потери
Настройка облачных серверов под продакшен без проверки сети – частая ошибка. Заявленный гигабит или 10 Gbps – это верхний предел, а не гарантированная полоса. Под длительной нагрузкой провайдеры нередко применяют шейпинг или rate limiting, и в документации это обычно не указано.
Базовый тест полосы между двумя нодами в одном датацентре (нужен iperf3-сервер на второй машине):
iperf3 -c <ip_сервера> -t 60 -P 4
В строке receiver смотреть на Bandwidth. Ключ -P 4 запускает 4 параллельных TCP-потока – один поток не всегда показывает реальный потолок канала: результат зависит от RTT, настроек TCP и доступного размера окна передачи. Параметр -t 60 задаёт длительность 60 секунд – этого достаточно, чтобы обнаружить burst-лимиты, если они есть.
UDP-тест для оценки потерь и jitter под заданной скоростью:
iperf3 -c <ip_сервера> -u -b 1G -t 30
Latency и jitter:
ping -c 1000 -i 0.1 <ip>
mtr --report --report-cycles 100 <ip>
Параметры виртуального интерфейса – если драйвер отдаёт данные (имя может отличаться: eth0, ens3 и т.п.):
ethtool eth0
В выводе mtr обращайте внимание на колонки Loss% и Last. Потери только на одном промежуточном хопе при нормальном трафике дальше – скорее всего, роутер деприоритизирует ICMP TTL-exceeded. Устойчивые потери на нескольких хопах подряд – другое дело.
Примерные ориентиры для внутрисетевого трафика в одном датацентре: RTT < 1 мс, потери = 0%, jitter < 0.5 мс. Реальные значения зависят от сети провайдера, маршрута и требований приложения. Устойчивые потери до конечного узла могут стать поводом разбираться.
Частые проблемы сети в облаке
Rate limiting и шейпинг. Если iperf3 даёт полную полосу первые 10–15 секунд, а затем резко снижает результат – провайдер применяет burst-лимиты. Реальная устойчивая полоса в таком случае ниже заявленной, и это нужно учитывать при выборе тарифа.
MTU в overlay-сетях. VXLAN и Geneve добавляют заголовок к каждому пакету, снижая эффективный MTU ниже стандартных 1500 байт – обычно до 1450. Пакеты с DF-флагом при этом дропаются без уведомления приложения.
Проверка MTU для IPv4 при стандартном MTU 1500:
ping -M do -s 1472 <ip>
Ответ «Frag needed» или «Message too long» означает, что пакет такого размера не проходит без фрагментации. Для IPv6, туннелей и нестандартных MTU значения будут другими. Нужно снижать TCP MSS или настраивать PMTUD на стороне приложения, иначе соединения будут зависать или деградировать непредсказуемо.
Нестабильный роутинг. Если mtr показывает устойчивые потери до конечного узла или аномальный рост RTT по маршруту – запустите повторно через 5–10 минут. Если ситуация не меняется – возможны BGP-флап, перегрузка маршрута или внутренний сбой у провайдера. В таком случае настройка облачных серверов внутри одного VPC не поможет – проблема на уровне сети провайдера или внешних аплинков.
Чек-лист проверки облачного сервера перед production
Последовательность шагов для оценки нового сервера перед миграцией:
1. Базовый срез в покое. Сразу после деплоя, до всякой нагрузки: vmstat 1 60, iostat -xz 1 60, ping к соседней машине в той же зоне. Запишите исходные значения st, await, avgqu-sz – это точка отсчёта для сравнения.
2. CPU steal под нагрузкой. Создайте реальную или приближенную к продакшену нагрузку (например, через stress-ng или аналог), параллельно мониторя vmstat 1. Сам по себе синтетический тест не гарантирует конкуренцию ресурсов на стороне гипервизора, поэтому важна динамика steal под фактической нагрузкой. Steal выше 3–5% под умеренной нагрузкой – повод проверить динамику, сопоставить её с p95/p99 и обратиться в поддержку. Причина может быть в ноде, тарифе или инфраструктуре провайдера.
3. Дисковый тест. fio с профилем нагрузки, близким к продакшену: 4K randread для OLTP, 1 MB sequential write для стриминга. Зафиксировать IOPS, await, avgqu-sz. В соседнем терминале – iostat -xz 1.
4. Сетевой тест. iperf3 минимум 60 секунд, ping с 1000 пакетами, mtr до ключевых endpoint’ов. Отдельно – проверка MTU: для стандартного MTU 1500 в IPv4 с ICMP можно использовать ping -M do -s 1472. Для IPv6, туннелей и нестандартных MTU значения будут другими.
5. Мониторинг 24–72 часа. Вывод в продакшен без наблюдения за суточным паттерном – ещё одна частая ошибка. sar с записью в файл или любой агент метрик (node_exporter, collectd) покажут поведение steal и await в разное время суток и помогут поймать пиковую конкуренцию на ноде.
6. Анализ p95/p99. Если есть возможность запустить реальное приложение или нагрузочную копию – собрать гистограмму latency за несколько часов. p95 и p99 в контексте всей системы точнее любого синтетического теста и позволяют напрямую сверить результат с SLO.
Одинаковые характеристики не означают одинаковую производительность. CPU steal, дисковый await и реальная полоса – три параметра, которые можно измерить заранее, не дожидаясь первого инцидента.
Все приведённые утилиты доступны в стандартных репозиториях Linux-дистрибутивов. Развернуть облачный сервер у провайдера, прогнать чек-лист по описанному порядку и сравнить результаты с ориентирами – это несколько часов работы. Это значительно меньше, чем стоит инцидент в продакшене, который можно было предотвратить.









































































