MAATRIX / Блог / Апгрейд тарифа четвёртый раз за год: пора на выделенный или пора чинить код

Апгрейд тарифа четвёртый раз за год: пора на выделенный или пора чинить код

MAATRIX

Вы в очередной раз открываете панель управления, чтобы поднять тариф VPS — и вдруг замечаете, что делаете это четвёртый раз за год. Сервер снова упирается в потолок по CPU или памяти, графики мониторинга красные, а разбираться некогда — проще нажать «апгрейд» и вернуться к работе. Проблема в том, что за этим одинаковым симптомом — частые апгрейды — прячутся два совершенно разных сценария, и от того, какой из них у вас на самом деле, зависит, тратите ли вы деньги на реальный рост или платите за то, чтобы не чинить код.

Два сценария с одним и тем же симптомом

С точки зрения панели управления оба сценария выглядят одинаково: раз в два-три месяца вы упираетесь в лимиты тарифа и берёте следующий по мощности план. Разница — в том, что стоит за ростом потребления ресурсов.

Сценарий 1: здоровый рост. Аудитория и нагрузка растут вместе с бизнесом. Больше пользователей — больше запросов к API, больше данных в базе, больше фоновых задач. CPU и память растут пропорционально росту реальных бизнес-метрик: числу активных пользователей, заказам, обращениям к API. Это хорошая проблема — она означает, что продукт работает и его используют больше, чем месяц назад. Апгрейд тарифа здесь — нормальная реакция на успех, и рано или поздно у такого проекта действительно наступает момент, когда VPS перестаёт быть адекватным инструментом и разумнее переходить на выделенный сервер — об этом отдельно и подробно в статье «Выделенный сервер против VPS: когда пора переезжать».

Сценарий 2: нездоровый паттерн. Пользователей примерно столько же, сколько было полгода назад, заказов не прибавилось, трафик на сайт не вырос — а сервер всё равно упирается в потолок снова и снова. Здесь апгрейд не решает проблему, а откладывает её: код течёт памятью, запросы к базе выполняются без индексов, кеш не работает или его вообще нет, и каждый следующий тариф закрывает симптом на два-три месяца, после чего всё повторяется. Деньги, потраченные на апгрейд, в этом случае не покупают рост — они покупают отсрочку.

Опасность второго сценария в том, что он не имеет верхнего предела в виде здравого смысла. Расходы на инфраструктуру растут, а первопричина — неэффективный код — никуда не девается и продолжает съедать ресурсы быстрее, чем растёт бизнес. Рано или поздно вы упрётесь либо в бюджет, либо в физический потолок мощности сервера, и тогда чинить архитектуру придётся всё равно, но уже в режиме аврала, а не спокойного профилирования.

Как отличить сценарий: сопоставьте ресурсы с бизнес-метриками

Самый надёжный способ разобраться, какой у вас сценарий, — не гадать по ощущениям, а сопоставить две кривые: рост потребления ресурсов и рост реальных бизнес-показателей за тот же период.

Возьмите историю апгрейдов за год и рядом с каждым запишите, что происходило с ключевой метрикой вашего продукта в тот же момент:

Дата апгрейдаБыло → стало (CPU/RAM)Активные пользователи / запросы в сутки
Январь2 vCPU / 4 ГБ → 4 vCPU / 8 ГБрост есть
Апрель4 vCPU / 8 ГБ → 6 vCPU / 16 ГБрост есть, но меньше
Июнь6 vCPU / 16 ГБ → 8 vCPU / 32 ГБпочти не изменилось
Август8 vCPU / 32 ГБ → 12 vCPU / 48 ГБпочти не изменилось

Это иллюстративный пример, а не универсальный шаблон — у вас цифры и метрики будут свои. Логика проверки одна: если потребление ресурсов растёт кратно быстрее, чем пользовательская база или число запросов, — перед вами, скорее всего, сценарий 2. Здоровый рост даёт примерно сопоставимые кривые: в полтора-два раза больше пользователей — примерно во столько же раз больше нагрузки. Если пользователей стало на 10-15% больше, а сервер за то же время пришлось увеличить вдвое — расхождение говорит само за себя.

Конкретные метрики, которые стоит сопоставлять:

  • RPS / запросы в сутки к API или сайту — против потребления CPU за тот же период.
  • Число активных пользователей (DAU/MAU) — против потребления RAM.
  • Размер базы данных в строках — против времени ответа типичных запросов (если размер вырос на 20%, а время ответа — в разы, дело не в объёме данных, а в отсутствующих индексах).
  • Число фоновых задач в очереди — против среднего размера кучи у процесса (рост при той же нагрузке — верный признак утечки).

Если готовых дашбордов с этими цифрами нет — не страшно, для первой прикидки хватит грубой сверки: посмотрите в биллинге даты и параметры апгрейдов, а рядом — данные аналитики или логи регистраций/заказов за те же месяцы. Даже без точных процентов расхождение обычно видно невооружённым глазом.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать VPS с запасом ресурсов

Профилирование перед очередным апгрейдом: куда смотреть в первую очередь

Если сопоставление ресурсов с метриками намекает на сценарий 2 — не спешите снова поднимать тариф. Прежде чем в пятый раз увеличивать мощность, стоит потратить время на профилирование и поискать конкретных виновников. Вот с чего начать.

Память. Постройте график потребления RAM за последние недели — пилообразный рост с перезапуском по OOM killer или по расписанию почти всегда означает утечку памяти. Разница между нормальным ростом кеша ОС (страничный кеш занимает свободную память и отдаёт её по требованию) и реальной утечкой — в том, что при утечке растёт RSS конкретного процесса приложения, а не файловый кеш. Подробный разбор, как поймать утечку по форме графика задолго до падения, — в статье «Утечка памяти в приложении: как поймать за неделю до падения».

Быстрая проверка:

# кто ест память прямо сейчас
ps aux --sort=-%mem | head -15

# растёт ли RSS процесса приложения во времени (снимайте раз в час)
grep VmRSS /proc/$(pgrep -f your_app | head -1)/status

Запросы к базе данных. Это вторая по частоте причина «раздувания» тарифа без реального роста нагрузки. Включите slow query log и посмотрите, какие запросы стабильно выполняются дольше 100-200 мс:

-- MySQL: включить лог медленных запросов
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 0.2;

-- PostgreSQL: то же через параметр в postgresql.conf
-- log_min_duration_statement = 200

Классические находки: запросы без индекса по полю в WHERE/JOIN, N+1 (ORM делает по одному запросу на каждую запись в цикле вместо одного JOIN), SELECT * там, где нужны три поля. Пошаговый разбор диагностики и исправления — в статье «MySQL: медленные запросы — причины и решение» — логика EXPLAIN и работы с индексами применима и к другим СУБД, не только к MySQL.

Отсутствие или неправильная работа кеша. Проверьте, насколько эффективно используется кеш, если он вообще есть:

redis-cli INFO stats | grep keyspace
# keyspace_hits и keyspace_misses — если misses сопоставимы с hits,
# кеш почти не работает и не снимает нагрузку с базы

Если кеша нет вовсе, а одни и те же данные (например, каталог товаров или конфиг) вычисляются заново на каждый запрос — это прямой кандидат на добавление кеширования до, а не вместо апгрейда тарифа.

Профилирование самого приложения. Если память и база выглядят нормально, а CPU всё равно упирается в потолок — нужен профайлер на уровне кода: py-spy или cProfile для Python, pprof для Go, встроенный profiler в Node.js, async-profiler для JVM. Как делать это безопасно на живом продакшене, не роняя сервис, подробно описано в статье «Профилирование приложения на проде без остановки» — короткие сэмплирующие сессии почти не создают overhead и не требуют даунтайма.

Типичные архитектурные проблемы, которые маскирует апгрейд

Апгрейд тарифа лечит симптом — нехватку ресурсов здесь и сейчас, — но не причину. Вот список того, что чаще всего скрывается за «нам просто нужно больше мощности»:

  • Утечки памяти. Незакрытые соединения с базой, растущие без ограничения кеши в самом приложении (in-memory кеш без TTL и без лимита размера), циклические ссылки в языках без trace-based сборщика мусора, забытые слушатели событий в долгоживущих процессах.
  • Отсутствие индексов или неоптимальные запросы. Особенно заметно, когда база выросла в размере — запрос, который отрабатывал за 5 мс при 10 тысячах строк, может занимать секунды при миллионе.
  • N+1 запросы. ORM незаметно превращает один логический запрос в сотни физических — это съедает и CPU, и число открытых соединений с базой, и легко остаётся незамеченным, пока нагрузка не начинает бросаться в глаза именно через рост требуемых ресурсов.
  • Отсутствие или неправильная стратегия кеширования. Кеш без TTL и без инвалидации — источник других проблем, но полное отсутствие кеша там, где данные меняются редко, а читаются часто, — прямая переплата за CPU и обращения к базе.
  • Отсутствие пулинга соединений. Каждое новое соединение с базой — это память и CPU на установку сессии. Без pgbouncer или встроенного пула соединений в ORM сервер может упираться в лимиты не из-за реальной вычислительной нагрузки, а из-за накладных расходов на постоянное открытие-закрытие соединений.
  • Синхронные блокирующие операции в горячем пути. Обращение к внешнему API, чтение с диска или тяжёлая сериализация прямо в обработчике запроса без очереди или кеша — то, что незаметно съедает CPU-время при росте параллельных запросов даже без роста уникальных пользователей.

Ни одна из этих проблем не лечится увеличением тарифа — она просто откладывается до следующего потолка.

Когда апгрейд — действительно правильное решение

Важно не удариться в другую крайность и не начать искать несуществующую утечку там, где на самом деле честный рост. Если сопоставление метрик из второго раздела показывает, что ресурсы растут более-менее пропорционально пользователям и запросам, а профилирование не находит явных аномалий (память стабильна, медленных запросов немного и они объяснимы объёмом данных, кеш работает с приличным hit rate) — апгрейд обоснован, и это нормальная плата за рост.

В этом случае стоит смотреть на апгрейды не изолированно, а в динамике: если тарифы приходится поднимать каждые два-три месяца именно из-за роста, а не из-за латания архитектурных дыр, рано или поздно вертикальное масштабирование на VPS упрётся в потолок — либо по цене (топовые VPS-тарифы стоят почти как младший выделенный сервер), либо по факту разделяемых ресурсов гипервизора. Признаки, что этот момент настал, и как выбрать конфигурацию при переходе, разобраны в статье «Выделенный сервер против VPS: когда пора переезжать». Там же — сравнение экономики VPS и выделенного сервера на длинной дистанции, если апгрейды продолжатся и дальше.

День на профилирование: план перед пятым апгрейдом

Если у вас уже было три-четыре апгрейда за год и сопоставление метрик намекает на сценарий 2, вот практичный план на один рабочий день — прежде чем снова просто увеличивать тариф.

Первые 2 часа — сбор данных, без изменений в коде.

  1. Выгрузите историю апгрейдов тарифа с датами и параметрами (обычно есть в биллинге панели управления).
  2. Рядом положите график ключевой бизнес-метрики (пользователи, заказы, запросы к API) за тот же период.
  3. Снимите текущий срез: ps aux --sort=-%mem, top -b -n 1, размер базы данных, hit rate кеша, если он есть.

Следующие 3 часа — включить логирование и профилирование.

  1. Включите slow query log на 2-3 часа под реальной нагрузкой, не под синтетическим тестом.
  2. Если подозреваете утечку памяти — снимите два-три среза RSS процесса с интервалом в час.
  3. Запустите короткую сэмплирующую профилировочную сессию (py-spy, pprof и аналоги) на одном инстансе, если приложение реплицировано.

Последние 2-3 часа — разбор находок и решение.

  1. Отсортируйте медленные запросы по суммарному времени (не по одиночной длительности) — часто не самый медленный, а самый частый запрос съедает больше всего ресурсов.
  2. Проверьте, растёт ли RSS без снижения между пиками нагрузки — это и есть сигнатура утечки.
  3. Оцените: если топ-3 находки (например, один запрос без индекса, одна утечка в фоновом воркере, отсутствующий кеш на горячем эндпоинте) явно объясняют потребление ресурсов — чините их, а не тариф. Если находок нет и всё выглядит architecturally здоровым — со спокойной душой берите следующий тариф или переходите к выделенному серверу.

Один день, потраченный на этот план, часто оказывается дешевле, чем очередной шаг вверх по тарифной сетке, — особенно если он один раз находит утечку или недостающий индекс, которые иначе продолжили бы требовать всё больше ресурсов при каждом следующем витке роста.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать VPS с запасом ресурсов

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Мы точно растём, но апгрейды всё равно кажутся слишком частыми — это нормально?

Да, если рост ресурсов примерно совпадает с ростом пользователей или трафика. Быстрый рост бизнеса иногда действительно требует апгрейда каждые два-три месяца — это не патология, а следствие успеха. Тревожный признак — не частота сама по себе, а расхождение между ростом ресурсов и ростом бизнес-метрик.

Профилирование ничего не нашло, а память и CPU всё равно растут — что делать?

Если явных утечек и медленных запросов нет, а нагрузка объективно растёт (сверено с бизнес-метриками), это, скорее всего, сценарий 1 — здоровый рост, и апгрейд оправдан. Стоит также проверить менее очевидные вещи: рост логов и временных файлов на диске, фоновые задачи, которые размножились без явного роста нагрузки, сторонние библиотеки с известными утечками (проверьте changelog на предмет фиксов памяти в новых версиях).

Можно ли профилировать продакшен без риска его уронить?

Да, если использовать сэмплирующие профайлеры с низким overhead (py-spy, async-profiler и аналоги) и короткие сессии по 30-60 секунд, а не постоянно включённый tracing-профайлер. Подробности безопасного подхода — в статье про профилирование на проде, ссылка выше.

Что делать, если чинить архитектуру физически некогда — команда маленькая?

Тогда осознанно выбирайте: платить за апгрейды как за временную отсрочку, зная, что это не решение, — и запланировать профилирование и фикс на ближайший спокойный спринт. Хуже — не осознавать, что вы платите за отсрочку, и удивляться, почему тариф снова не хватает через два месяца.

Как часто стоит повторять эту проверку — сопоставление ресурсов с метриками?

Разумно делать это при каждом апгрейде, а не только при четвёртом за год. Тогда сценарий 2 ловится на первом-втором апгрейде, а не после того, как накопится история из четырёх недёшевых повышений тарифа.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →