Я пишу это не как негативный отзыв о REGXA и не пытаюсь говорить кому-либо, стоит или не стоит покупать у них VPS. Это просто один из моих рабочих дней как разработчика.
Я перенёс обычную нагрузку на KVM VPS с 2 vCPU, 2 GB RAM и 60 GB NVMe. Nginx работал. Backend работал. Но сервер вёл себя так, будто был чудовищно перегружен: запросы копились, TLS-операции замедлялись, соединения долго оставались открытыми, а некоторые запросы в итоге возвращали HTTP 504 только спустя более двух минут.
Учёт CPU полностью изменил направление диагностики
Первая мысль была очевидной: что-то внутри VPS съедает процессор. Я запустил mpstat.
Average CPU steal: 92.58%
CPU 0 steal: 90.62%
CPU 1 steal: 94.57%
CPU user: 4.02%
CPU system: 1.47%
CPU iowait: 0.41%
CPU idle: 0.53%
Отдельные замеры снова и снова показывали примерно 89–98% steal. CPU pressure тоже был экстремальным:
CPU PSI some avg10: 79.47
CPU PSI some avg60: 75.32
CPU PSI some avg300: 76.31
Load average: 5.85 / 5.75 / 5.73
Это была машина всего с двумя vCPU. В Linux были runnable-процессы, ожидавшие CPU. Главным показателем была не обычная загрузка процессора приложениями, а %steal.
Высокая загрузка CPU и CPU steal — разные проблемы
Если бы моё приложение действительно загружало процессор, я ожидал бы высокие значения user или system. Вместо этого VPS выглядел примерно так:
user: 4%
system: 1%
steal: 93%
CPU steal — это время, когда виртуальный процессор готов выполнять работу, но гипервизор его не планирует. Поэтому, когда я говорю, что у VPS забиралось процессорное время, я имею в виду именно этот технический смысл из виртуализации. Я не могу доказать, что REGXA намеренно передала другому клиенту физические ядра, которые якобы были эксклюзивно моими, и по guest-метрикам невозможно установить намерение. Но я могу доказать, что у гостевой системы регулярно была готовая к выполнению работа, а процессорного времени она не получала.
Я полностью убрал production-трафик
Оставалось разумное возражение: возможно, проблему всё-таки создавала моя нагрузка. Я убрал эту переменную. Активный workload перенёс на другой сервер, production-трафик на этот VPS прекратил, дождался очистки очередей и повторил измерение.
Average CPU steal: 94.17%
CPU 0 steal: 95.56%
CPU 1 steal: 92.83%
CPU user: 1.95%
CPU system: 0.59%
CPU iowait: 0.59%
CPU idle: 2.18%
Результат стал ещё хуже. Отдельные выборки vmstat по-прежнему показывали 91–98% steal, а CPU ожидали до 15 runnable-процессов. Самой важной была эта комбинация:
user: 1.95%
system: 0.59%
steal: 94.17%
Мои приложения теперь почти ничего не делали, но VM всё равно теряла почти всё процессорное время на ожидании планирования. Обычная production-нагрузка перестала быть правдоподобным объяснением.
Даже localhost стал абсурдно медленным
Я также протестировал HTTPS через 127.0.0.1, исключив из эксперимента публичный DNS, моего провайдера, географическое расстояние и внешний сетевой маршрут.
Под нагрузкой четыре из десяти localhost HTTPS-запросов падали ещё на TLS handshake. Успешные запросы занимали 29,30, 22,77, 12,25, 11,87, 11,12 и 9,40 секунды. Некоторые TLS handshake сами по себе длились около девяти секунд.
После снятия production-трафика localhost стал быстрее, но оставался крайне нестабильным: 0,061, 0,745, 0,830, 0,873, 1,010, 1,117, 1,121, 2,188 и 3,355 секунды. Одна и та же локальная операция могла один раз занять около 61 ms, а следующий — больше 3,3 секунды.
Остальной стек показывал последствия
В один момент я видел примерно 450 established-соединений, 122 orphaned-соединения, 110 FIN-WAIT-1 и 33 CLOSE-WAIT. Listen queue локального backend доходила примерно до 14–15, а HTTPS — до 40.
Nginx фиксировал HTTP 504 спустя 142,857, 138,902, 135,064, 129,819 и 128,657 секунды. Другие запросы оставались открытыми примерно 67–130 секунд. Я также видел secure-connect timeout примерно через 35–41 секунду, database network timeout и задержки TLS.
По отдельности всё это легко принять за разные проблемы Nginx, базы данных, сети или backend. Но увеличение таймаутов не создаёт CPU time, которое гипервизор не планирует.
RAM и диск это не объясняли
На VPS оставалось примерно 1,0–1,1 GiB доступной RAM, swap почти не использовался, OOM-событий и активности OOM killer не было. Файловая система была заполнена только примерно на 20%, свободно оставалось около 44 GB. I/O wait во время ключевых CPU-замеров был ниже 1%.
Память не закончилась, диск не был заполнен, и мои приложения не потребляли пропавший CPU. Доминирующей метрикой оставался %steal.
Здоровый KVM VPS выглядел совершенно иначе
Я провёл тот же тип диагностики на другом KVM VPS, который в этот момент обслуживал обычный трафик:
Average CPU steal: 0.02%
CPU idle: 87.86%
CPU PSI avg10: 0.29
CPU PSI avg60: 0.63
CPU PSI avg300: 0.49
Load average: 0.47 / 0.33 / 0.14
Его десять localhost HTTPS-запросов выполнялись примерно за 37–69 ms. Позже на другом действительно загруженном production VPS я измерил 61,71% user CPU, 5,08% system CPU, 24,09% idle и всего 0,13% steal.
Именно это различие теперь для меня принципиально. VPS может быть занят потому, что мой софт действительно использует процессор. Это совсем не то же самое, что гостевая система, которая более 90% измеренного CPU time ждёт гипервизор.
REGXA в итоге подтвердила инфраструктурный contention
Изнутри VM я мог измерять гостевую систему, но не видел физический host, конфигурацию scheduler, CPU quota и соседние VM. REGXA это видеть могла.
В итоге поддержка сообщила, что VPS размещён на shared CPU infrastructure, CPU-ресурсы разделяются между несколькими виртуальными машинами, а производительность может зависеть от нагрузки на физический node. Они также сказали, что инфраструктура во Frankfurt испытывала особенно высокий спрос, и прямо связали мой повышенный CPU steal с resource contention on the underlying infrastructure.
Поддержка уточнила, что не может изменить CPU quota или scheduling policy и не может выделить дополнительные dedicated CPU resources этому shared VPS на текущей инфраструктуре. В качестве технического решения предложили перенос в location с меньшей загрузкой.
Мне было трудно совместить это объяснение с формулировками, которые я видел про dedicated CPU cores и guaranteed resources. Я не вижу точную конфигурацию host, поэтому не могу сказать, был ли непосредственным механизмом CPU overcommitment, quota, scheduler weighting, throttling или их комбинация. Намерение я тоже доказать не могу. И не обязан: Linux стабильно показывал 92–94% steal, а сама REGXA связала повышенный steal с contention на shared-инфраструктуре.
За полный возврат денег тоже пришлось побороться
Когда инфраструктурная причина стала ясна, я не хотел продолжать переносить VPS и проверять другие node. Я хотел отменить услугу и вернуть деньги.
Сначала мне предложили только часть суммы, причём возврат предполагался на внутренний баланс REGXA, а не обратно на карту, которой я платил. Для меня кредит у провайдера не равен возврату денег, когда я пытаюсь уйти из сервиса.
Поэтому я продолжал переписку и просил вернуть 100% платежа на исходный способ оплаты. В итоге REGXA согласилась и вернула всю сумму на первоначальный метод оплаты, обозначив полный refund как исключение.
Я ценю, что в итоге вернули всё. Но то, что после признания инфраструктурного contention мне пришлось отдельно додавливать финансовую часть, тоже является частью моего опыта.
Главный вывод, который я оставил себе
Самой простой ошибкой было бы продолжать оптимизировать приложение. Я мог менять Nginx, увеличивать таймауты, снижать concurrency, добавлять retries, разбирать MongoDB или переписывать backend. Возможно, часть симптомов изменилась бы. Но ничего из этого не ответило бы на главный вопрос: почему CPU steal выше 90%?
Теперь я не ограничиваюсь тем, что SSH работает, Nginx запускается, а health endpoint отвечает 200. На новом VPS я также смотрю %user, %system, %iowait, %idle, %steal, CPU PSI, run queue и localhost latency.
Если что-то выглядит подозрительно, я снимаю нагрузку и измеряю снова. В этой истории именно такой тест дал самый чистый результат:
CPU user: 1.95%
CPU system: 0.59%
CPU steal: 94.17%
Я не утверждаю, что каждый VPS у REGXA ведёт себя так. Я протестировал один VPS и документирую то, что произошло именно с ним. Но на этой машине доказательства были необычно ясными: мои приложения почти не потребляли CPU, тогда как Linux показывал, что подавляющая часть виртуального CPU time теряется в ожидании scheduling со стороны гипервизора. Позже REGXA связала именно это поведение с resource contention на своей shared-инфраструктуре.
Поэтому я и пишу об этом. Не как оценку и не как рекомендацию, а просто как ещё один день из жизни разработчика — и как напоминание о метрике, которую я больше никогда не буду игнорировать на VPS.