У многих команд есть сервер, который называется staging, и счёт за него приходит ровно так же регулярно, как за боевой. Заходят на него редко: раз в две недели кто-то выкатывает ветку, неделю никто не вспоминает, потом выясняется, что там лежит версия базы полугодовой давности, а часть сервисов давно не запускается. Деньги платятся, а уверенности в релизе эта среда не прибавляет. Хочется её просто выключить или ужать до самого дешёвого тарифа. Оба решения могут оказаться ошибкой, и чтобы понять почему, придётся сначала спросить не «сколько стоит сервер», а «что именно мы на нём проверяем».

Сначала испытание, потом размер сервера

Слово «staging» скрывает как минимум три разных работы. Каждая требует от окружения своего набора свойств, и совпадают эти наборы лишь частично.

Проверка интерфейса и бизнес-логики: кнопка работает, форма отправляется, письмо уходит, права доступа различаются по ролям. Здесь важны версии кода, конфигурация, набор интеграций и то, чтобы данные выглядели похоже на живые. Мощность процессора почти не имеет значения: если приложение открывается за секунду или за две, смысл проверки не меняется.

Репетиция миграции базы данных. Тут картина другая. Нужны та же версия СУРБД, те же расширения, тот же порядок миграций и данные с реальной структурой: с теми же индексами, внешними ключами, перекосами в распределении значений и «грязными» старыми записями, о которых никто не помнит. Объём диска и скорость операций ввода-вывода важны, если вы хотите узнать, сколько времени займёт изменение большой таблицы. Если вопрос только в том, пройдёт ли миграция без ошибки, достаточно меньшего набора данных, но с теми же особенностями.

Проверка под нагрузкой. Это самый требовательный сценарий: чем ближе ресурсы, конфигурация и сеть к боевым, тем осмысленнее результат. Но требовательность у него временная. Нагрузочная репетиция длится десятки минут или несколько часов, а не весь месяц.

Если смешать всё это в одну среду «на всякий случай», получится либо слишком дорогая копия production, либо слишком слабая песочница, которая ничего не доказывает. Поэтому разумный путь к экономии начинается с таблицы потребностей.

Что нужно от среды в зависимости от вопроса
Вопрос проверкиЧто должно совпадать с productionЧто можно уменьшить
Работает ли интерфейс и сценарий пользователяВерсии приложения, конфигурация, интеграции, ролиCPU, RAM, объём данных, число реплик
Пройдёт ли миграция БДВерсия СУРБД, схема, индексы, форма данных, порядок миграцийЧасть объёма; ядра, если не меряем время
Хватит ли системе ресурсовРесурсы, конфигурация, профиль запросов, объём данныхПочти ничего, зато срок жизни среды короткий

Из таблицы видно главное: «урезать всё одинаково» не работает. Одна и та же экономия, допустим вдвое меньше памяти, безвредна для проверки формы и разрушительна для репетиции нагрузки.

Что значит «похоже на production» и где остановиться

Методология Twelve-Factor App в разделе о паритете окружений советует сокращать разрыв между разработкой, тестированием и production: по инструментам, по времени между изменением и выкаткой и по людям, которые пишут код и эксплуатируют его (The Twelve-Factor App: Dev/prod parity). Это полезный ориентир, но он не требует одинакового размера серверов. Различия бывают разной цены и разной опасности, и экономить стоит на тех, которые не искажают результат.

Практический способ разобраться: выписать всё, чем staging отличается от боевой среды, и против каждого пункта поставить вопрос, способен ли этот пункт изменить исход конкретной проверки. Например:

  • Другая версия СУРБД может скрыть ошибку миграции или, наоборот, создать ложную. Это отличие нельзя оставлять.
  • Другой тип диска влияет на время тяжёлой миграции, но не влияет на то, корректна ли она. Для проверки корректности его можно упростить, для оценки окна обслуживания нельзя.
  • Подменённый почтовый или платёжный сервис на заглушку обычно допустим, но тогда у вас появляется непроверенный участок: реальный обмен с внешней системой. Его надо учитывать как известный пробел.
  • Меньше ядер и памяти для приложения не мешает проверять логику, но делает бессмысленным любое суждение о производительности.

Здесь же стоит вспомнить про версии образов. Если контейнеры собираются по тегам вроде «latest» или «стабильной ветки», то staging и production могут незаметно оказаться на разных образах просто потому, что их подтягивали в разное время. Документация Docker указывает, что теги образов изменяемы, а фиксация по digest закрепляет конкретный образ (Docker build best practices). Побочный эффект тоже описан: закреплённый образ не получает будущие исправления сам, его обновление требует отдельного действия. Для staging это означает дисциплину: версии, которые вы проверяли, должны быть теми же, которые уйдут в production, а обновление базового образа превращается в осознанное событие, которое тоже проходит через проверку. Стоит такая дисциплина копейки по сравнению с вычислительными ресурсами, а паритет версий она обеспечивает лучше, чем мощный сервер.

Размер данных и структура данных: две разные величины

Основная статья расходов на staging обычно не процессор, а диск, потому что хочется иметь «копию боевой базы». Тут полезно развести два свойства данных, которые мы привыкли склеивать.

Размер определяет, сколько места занимают таблицы и индексы, как долго идёт полное сканирование, как ведёт себя кэш. Структура определяет схему, связи, диапазоны значений, долю пустых полей, перекос (когда один клиент владеет половиной записей), редкие типы записей и исторические странности. Большинство ошибок миграций и интерфейсов вызвано именно структурой: поле, которое «никогда не бывает пустым», а в старых строках пустое; кодировка, которая сломалась в 2017 году; запись, ссылающаяся на удалённого родителя.

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

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

Исключение составляет репетиция, где размер сам является предметом проверки. Если нужно узнать, за сколько изменится таблица на несколько сотен миллионов строк или как поведёт себя план запроса при реальном объёме, придётся иметь соответствующий объём, пусть и не постоянно. Здесь мы подходим к следующему вопросу: нужно ли держать такую среду всегда.

Среда на всё время или среда под работу

У постоянно доступного staging есть понятная ценность: любой участник команды может выкатить ветку, показать её заказчику, поправить и повторить. Ничего не надо ждать. Такое окружение выполняет роль общей рабочей площадки, а общая площадка нужна, когда в проекте много параллельных изменений или есть несколько человек, которым нужна обратная связь на реальных страницах.

У среды «под работу» другая логика: её создают к нужному моменту (предрелизная проверка, репетиция миграции, нагрузочный прогон) и убирают потом. Деньги платятся только за период использования, а размер можно подобрать точно под задачу, не оглядываясь на повседневные нужды.

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

Например, один сервер можно использовать в обычные недели как лёгкий staging для проверки интерфейса, а перед крупным релизом остановить на нём привычные сервисы и провести репетицию. Но тогда возникает цена, о которой в счёте за сервер ничего не написано.

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

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

АРЕНДОВАТЬ СЕРВЕР

Труд на восстановление: невидимая строка бюджета

Каждый раз, когда среда создаётся заново или переделывается под другую задачу, кто-то должен привести её в рабочее состояние. Развернуть базу нужной версии, загрузить набор данных, поднять сервисы, прописать секреты и адреса, проверить, что сборка соответствует production. Если всё это делается руками по памяти, час-два работы инженера легко перекрывают выгоду от экономии на сервере.

Условный пример, чтобы почувствовать масштаб. Допустим, команда решила держать большую среду только перед релизами, шесть раз в год, и каждый раз тратить на подготовку четыре часа работы разработчика. Это двадцать четыре часа в год. Если стоимость часа внутри компании измеряется сотнями или тысячами рублей, получится сумма, сравнимая с несколькими месяцами аренды небольшого сервера. А если подготовка идёт не четыре часа, а целый день, к тому же с ошибками и повторами, выигрыш исчезает. Цифры здесь иллюстративные: подставьте свои.

Следовательно, ставка на «поднимать по требованию» оправдана, только когда подъём автоматизирован и воспроизводим. Что для этого нужно:

  • описание окружения в виде файлов, а не в чьей-то голове: конфигурация сервисов, версии образов (с фиксацией по digest, как говорилось выше), переменные окружения без секретов в репозитории;
  • воспроизводимый способ наполнения базы: скрипт, который создаёт обезличенный или сгенерированный набор данных, а не ручная выгрузка;
  • проверка после подъёма: короткий набор запросов, подтверждающий, что среда живая и версии совпадают с ожидаемыми, прежде чем кто-то начнёт на ней тестировать;
  • понятная запись о том, как среду убрать или обновить, чтобы она не превратилась снова в забытый сервер.

Эти работы дороги один раз, но потом уменьшают стоимость каждого запуска. И они же снижают главный скрытый риск постоянно живущего staging: дрейф. Среда, на которой полгода делали руками «быстрые правки», перестаёт быть похожей на production, и тесты на ней становятся театром. Пересоздание из описания заодно лечит дрейф.

У постоянной среды тоже есть свой труд: поддержание в актуальном состоянии. Кто обновляет базу, кто чистит диск, кто следит, чтобы версия не отстала от боевой. Если ответственного нет, то фактически вы платите за сервер и получаете деградирующую копию.

Репетиция нагрузки: где экономить нельзя и как не обмануться

Нагрузочная проверка чаще всего и разваливает идею «дешёвого staging». Если сервер вдвое слабее боевого, результат вдвое менее интересный: вы не знаете, как масштабируется ваша система, линейно ли, и какое из узких мест проявится раньше. Поэтому для такой работы разумнее отдельное короткое окружение, максимально близкое по ресурсам и конфигурации к production, чем постоянная маленькая копия, на которой нагрузку «примерно прикидывают».

Из линейки MAATRIX здесь можно ориентироваться на ресурсы тарифов как на отправную точку: Ba — 1 vCPU, 2 ГБ RAM, 40 ГБ NVMe; Uab — 2 vCPU, 4 ГБ, 80 ГБ; Heka — 4 vCPU, 8 ГБ, 160 ГБ; Maat — 8 vCPU, 16 ГБ, 240 ГБ; Djed — 16 vCPU, 32 ГБ, 320 ГБ (каталог VPS). Эти цифры описывают ресурсы, а не гарантированную ёмкость: сколько пользователей выдержит ваше приложение на Heka или Maat, покажет только замер. Поэтому разумно подобрать для репетиции тариф, соответствующий вашему production по ресурсам, и использовать результаты как данные о вашей системе, а не как обещание.

Второе, от чего зависит ценность нагрузочной проверки, это заранее заданные критерии успеха. Инструмент нагрузочного тестирования k6 предлагает для этого пороги (thresholds): условия прохождения теста по метрикам вроде задержки или доли ошибок, и если условие не выполнено, результат теста считается неуспешным (Grafana k6 thresholds). Мысль полезна независимо от инструмента: прежде чем запускать репетицию, надо договориться, какой результат считается приемлемым. Иначе график просто разглядывают и находят в нём то, что хочется увидеть. Пороговые значения из примеров документации не подходят вашему сайту как готовые цифры: свои пределы по задержке и ошибкам вы выводите из требований продукта и из того, что видите в production.

Остаётся вопрос, чем нагрузка из теста отличается от настоящей. Если в боевой среде сложный профиль запросов (часть пользователей листает каталог, часть оформляет заказы, фоновые задачи конкурируют за базу), то простой скрипт, бьющий по одной странице, покажет красивые числа, не относящиеся к делу. Профиль нагрузки входит в «свойства production, которые надо сохранить», так же как версия СУРБД.

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

Три конфигурации вместо одной «средней»

Теперь можно собрать всё в практическую схему. Вместо одного сервера, которому приходится быть всем, получается несколько ролей с разной ценой владения.

  1. Постоянная лёгкая среда для интерфейса и логики. Небольшой VPS, версии образов совпадают с боевыми, данные синтетические или обезличенные, структура и редкие случаи сохранены. Задача: показывать ветки команде и заказчику, ловить функциональные ошибки. Предел: о производительности и времени миграций она ничего не говорит, и это записано в её описании.
  2. Репетиционная среда для миграций. Поднимается перед изменением схемы, с версией СУРБД как в production и набором данных, достаточно близким по структуре, а если нужно оценить время, то и по объёму. Диска и скорости ввода-вывода здесь нужно больше, чем процессора. Срок жизни определяется условиями оплаты, поэтому считать её имеет смысл как ресурс на выбранный период.
  3. Нагрузочная среда. Ресурсы близки к боевым, пороги успеха заданы заранее, профиль нагрузки описан. Её используют в окне перед крупными релизами, а в остальное время она либо не существует, либо переиспользуется под другую роль.

Эти роли можно частично совмещать на одном сервере по очереди, если подъём автоматизирован. А можно держать лёгкую среду отдельно, а остальные брать на период. Какой вариант дешевле, зависит от частоты релизов, величины базы и стоимости времени команды, а не от абстрактного правила.

Как посчитать расходы вместе с ценой плохого теста

Обычный расчёт стоимости staging складывает аренду серверов. Для честной картины нужны ещё три слагаемых.

  • Труд на подготовку и поддержку. Часы на подъём, обновление данных, исправление дрейфа, умноженные на частоту.
  • Цена ошибки, пропущенной из-за непоказательной среды. Если миграция прошла на маленькой базе, а в production блокирует таблицу на сорок минут, ущерб складывается из простоя, срочной работы и потери доверия. Размер этой суммы надо оценить по вашим данным: сколько стоит час недоступности, как часто бывают такие случаи.
  • Цена ложной уверенности. Самое неприятное: среда, которая всегда «зелёная», потому что ничего сложного не проверяет. Деньги за неё потрачены, а решения на основе её результатов принимаются как на основе знания.

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

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

Меньше, но с известными пределами

Хороший результат этих рассуждений не обязательно дешевле прежнего. Он честнее. Вместо «копии production» появляется набор небольших сред, у каждой из которых записано, зачем она нужна, что на ней совпадает с боевой системой, а что нет, и о чём её результаты говорить не вправе. Лёгкий staging не отвечает на вопросы о нагрузке. Репетиция миграции не заменяет проверку интерфейса. Нагрузочный прогон не доказывает, что письма доходят по реальному адресу.

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