MAATRIX / Блог / База растёт быстрее выручки: рост по данным, который никто не планировал

База растёт быстрее выручки: рост по данным, который никто не планировал

MAATRIX

Раз в квартал команда смотрит на выручку, число активных пользователей, конверсию — и всё выглядит нормально, рост есть, пусть и не взрывной. Про базу данных при этом обычно не думают вообще, пока не приходит счёт за диск побольше или алерт "осталось 10% места". А когда наконец смотрят — база выросла в разы сильнее, чем бизнес, который она обслуживает. Это не всегда чья-то ошибка: чаще это накопленный эффект нескольких источников роста, которые никто явно не проектировал и не считал отдельной метрикой. Разберём, откуда берётся такой рост, чем он опасен для экономики проекта и как его увидеть раньше, чем он станет проблемой.

Почему рост данных остаётся невидимым

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

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

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

Ниже — три типовых источника, из-за которых база уходит от размера, логично ожидаемого при данном масштабе бизнеса.

Источник первый: логи и аудит-записи без срока жизни

Самый частый и незаметный источник — таблицы аудита и журналы событий: audit_log, user_events, activity_log — кто что сделал, когда, с каким результатом. Решение правильное с точки зрения безопасности и отладки, но у него есть особенность, которую редко проговаривают на этапе проектирования: такая таблица растёт с каждым действием каждого пользователя, а не с каждым новым пользователем.

Если у вас 1000 активных пользователей и каждый совершает в среднем 50 действий в день, аудит-таблица прирастает на 50 000 записей ежедневно — независимо от того, растёт бизнес или стоит на месте. Стала функция популярнее — прирост ускоряется без единого нового клиента. Рост здесь отвязан от выручки почти полностью.

Проблема усугубляется тем, что у таких таблиц почти никогда с самого начала не прописан срок хранения — вопрос "сколько нам это реально нужно" на старте просто не встаёт. В результате таблица растёт бессрочно, и через год-два оказывается крупнее всех "полезных" бизнес-таблиц вместе взятых.

Проверить масштаб быстро. В PostgreSQL:

SELECT relname AS table_name,
       pg_size_pretty(pg_total_relation_size(relid)) AS total_size,
       n_live_tup AS row_estimate
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 15;

В MySQL — через information_schema:

SELECT table_name,
       ROUND((data_length + index_length) / 1024 / 1024, 1) AS size_mb,
       table_rows
FROM information_schema.tables
WHERE table_schema = 'your_database'
ORDER BY (data_length + index_length) DESC
LIMIT 15;

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

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

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

Арендовать VPS

Источник второй: версии, снапшоты и soft-delete без архивации

Второй источник — исторические данные внутри самих бизнес-таблиц: версии документов, снапшоты состояний, записи, помеченные удалёнными вместо реального удаления (soft delete). Все три паттерна разумны и часто необходимы: версионирование даёт откат и историю изменений, soft delete защищает от случайной потери и сохраняет ссылочную целостность.

Проблема не в паттернах, а в том, что они почти никогда не сопровождаются симметричным процессом архивации. Записать версию при каждом изменении — одна строка кода. А задача "перенести версии старше года в холодное хранилище" или "удалить soft-deleted записи по истечении срока" почти никогда не реализуется в том же спринте — откладывается на потом, а потом не наступает: явного триггера нет, база не падает, все довольны.

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

Практическая проверка — соотношение "живых" и помеченных строк:

SELECT
    COUNT(*) FILTER (WHERE deleted_at IS NULL) AS active_rows,
    COUNT(*) FILTER (WHERE deleted_at IS NOT NULL) AS soft_deleted_rows
FROM orders;

Если soft-deleted строк в разы больше активных — сигнал, что процесс работает только наполовину: пометка есть, а архивации или окончательного удаления по сроку нет. Разумная схема — не хранить такие записи в основной таблице бессрочно, а через N дней переносить в архив или удалять, если бизнес-причин хранить дольше нет. Аналогично с версиями: держать в горячей таблице последние K версий или версии за последние M месяцев, остальное — сжимать и переносить.

Источник третий: данные, которые генерируют не пользователи, а процессы

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

У такого рода данных своя логика роста, не связанная с клиентской базой. Пример: интеграция, которая раз в час опрашивает состояние заказов и на каждый опрос пишет строку в таблицу истории синхронизации, — она растёт строго по расписанию крона, независимо от числа клиентов. Другой пример: очередь, которая сохраняет каждое обработанное сообщение "на всякий случай" для отладки — объём таблицы определяется частотой внутренних событий, а не пользователями снаружи.

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

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

Почему это бьёт по экономике проекта незаметно

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

Здесь два разных бюджета, которые растут вместе с базой, но по-разному:

  • Стоимость самого хранилища. Диск под боевую базу — обычно быстрый NVMe — стоит дороже холодного хранилища в разы. Каждый лишний гигабайт неубранных логов или версий занимает место по цене горячего диска, хотя к нему почти никто не обращается.
  • Стоимость и время бэкапов. Растут вместе с базой: полные копии дублируют весь лишний объём, инкрементальные снижают ежедневный прирост, но не решают проблему базового размера. Время резервного копирования и восстановления растёт вместе с объёмом — это отдельный операционный риск: чем больше база, тем дольше окно бэкапа и дольше реальное время восстановления (RTO) после сбоя.

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

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

Как диагностировать: смотреть не на общий размер, а на то, что растёт

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

Практическая последовательность:

  1. Снимать размеры таблиц регулярно — не разово, а с фиксированной периодичностью, раз в неделю или в месяц. Запросы для PostgreSQL и MySQL приведены выше; для MongoDB аналог — db.runCommand({collStats: "collection_name"}) для отдельной коллекции или db.stats() в связке с перебором коллекций.
  2. Сохранять историю снимков, а не только текущее состояние — иначе снова придётся гадать, был ли рост плавным или скачкообразным и когда начался. Достаточно простой таблицы или CSV-файла с колонками "дата, таблица, размер".
  3. Сравнивать темп роста таблицы с темпом роста бизнес-метрики, которая логически должна её объяснять. Таблица заказов растёт пропорционально числу заказов — это ожидаемо. Таблица аудит-логов растёт в разы быстрее числа активных пользователей — сигнал посмотреть, что туда пишется и с какой частотой.
  4. Для каждой из топ-таблиц по размеру задать вопрос: есть ли для неё политика хранения? Не абстрактно "когда-нибудь почистим", а конкретно: срок хранения в горячем доступе, что происходит после его истечения — архивация, сжатие, перенос в холодное хранилище или удаление, — и кто отвечает за то, чтобы это происходило автоматически, а не по чьей-то памяти. Если ответа нет — это и есть корень несоразмерного роста, а не сам рост как таковой.

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

Тип данныхДрайвер ростаНа что смотреть при задании срока
Аудит-логи, журналы действийАктивность пользователей, не их числоТребования комплаенса, частота обращения к старым записям
Версии документовЧастота редактирования, не число документовСколько версий назад реально когда-либо запрашивали
Soft-deleted записиЧастота удаленийСрок, после которого восстановление уже не запрашивают
Данные фоновых процессовРасписание и логика самого процессаНужна ли история дольше последних N запусков для отладки

Рост данных — отдельная метрика, а не побочный эффект

Ключевой практический вывод: рост данных не стоит рассматривать как то, что "просто происходит" вместе с работой системы. Это отдельная метрика, у которой должен быть свой регулярный обзор — так же, как у выручки есть ежемесячный отчёт, а у инфраструктуры — мониторинг доступности.

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

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

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

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

Арендовать VPS

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

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

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

С чего начать, если раньше не смотрели на размер таблиц по отдельности?

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

Обязательно ли удалять старые данные, или достаточно архивировать?

Зависит от того, нужны ли они хоть иногда. Активные бизнес-данные, к которым редко, но обращаются (старые заказы, документы), правильнее архивировать — перенести в дешёвое холодное хранилище, сохранив доступ. Чисто техническая история без ценности для бизнеса и без требований комплаенса — можно удалять по расписанию, не тратя ресурсы даже на архив.

Как быть с требованиями хранить логи определённый срок по закону или договору?

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

Что делать, если рост объясняется одним конкретным фоновым процессом, который нельзя отключить?

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

Как часто реально нужно пересматривать рост данных как метрику?

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

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

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

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