Capacity planning: CPU, RAM, IOPS, соединения и рост данных
↑ Этап 7 · Эксплуатация и безопасность БД
Зачем это на собесе
Планирование ёмкости предотвращает аварии «закончилось место/соединения» и помогает обосновать бюджет.
Зачем
Ответить заранее на вопросы: когда закончится диск? Выдержит ли БД рост нагрузки вдвое? Сколько ресурсов нужно под пик? Когда пора масштабироваться?
Метод: измерить текущее → смоделировать рост → добавить запас → договориться о пороге действий → проверить нагрузочными тестами.
Ресурсы
CPU
Определяется сложностью запросов и числом одновременно активных сессий. Ориентир для OLTP: активных соединений не более cores × 2..4; больше — очереди и переключение контекста. Метрики: загрузка, load average, steal (в облаке), доля ожидания I/O. Параллельные запросы используют несколько ядер (max_parallel_workers).
Память (RAM)
| Параметр | Роль |
|---|---|
shared_buffers | ~25% RAM |
| Кэш ОС | остальная память: «горячие» данные должны помещаться (working set) |
work_mem | на каждую операцию сортировки/хэша каждого запроса: work_mem × операций × соединений |
maintenance_work_mem | VACUUM, индексы |
| Память процессов | ~5–10 МБ на соединение + кэши |
Цель: рабочий набор данных и индексов помещается в память (cache hit > 99%). Признаки нехватки: рост blks_read, сортировки на диск, swap, OOM killer.
Диск (объём и IOPS)
- Объём: данные + индексы + bloat + WAL + временные файлы + бэкапы/архив WAL + запас на VACUUM FULL/перестроение индексов (до 2× таблицы);
- IOPS и пропускная способность: случайные чтения (индексы), запись WAL (последовательная), checkpoint;
- Задержка (latency): критична для
fsyncWAL (коммиты); - типы: NVMe/SSD для OLTP; отдельные тома для WAL и данных (опционально);
- облако: лимиты IOPS/throughput тома (gp3, io2), «burst credits» (исчерпание приводит к падению производительности).
SELECT pg_size_pretty(pg_database_size('app')) AS db,
pg_size_pretty(sum(pg_total_relation_size(c.oid))) AS tables_and_indexes
FROM pg_class c WHERE c.relkind IN ('r','m','t');
SELECT relname, pg_size_pretty(pg_total_relation_size(oid)) AS total,
pg_size_pretty(pg_relation_size(oid)) AS heap, pg_size_pretty(pg_indexes_size(oid)) AS idx
FROM pg_class WHERE relkind = 'r' ORDER BY pg_total_relation_size(oid) DESC LIMIT 10;Соединения
max_connections (по умолчанию 100) и реальное число клиентов (сервисы × размер пула). Формула для размера пула приложения: pool_size ≈ (cores × 2) + effective_spindle_count для одной БД суммарно; а не «максимум на всякий случай». Используйте PgBouncer; мониторьте numbackends / max_connections, очереди ожидания пула (cl_waiting).
Сеть
Пропускная способность и задержка (репликация, бэкапы, большие выборки), межзональный трафик.
Рост данных и прогноз
- Собрать историю: размер БД и таблиц раз в сутки (таблица
db_size_history, Prometheuspg_database_size_bytes). - Определить тренд: линейный (
predict_linearв Prometheus) или экспоненциальный; учесть сезонность (распродажи, отчётные периоды). - Драйверы роста: число пользователей, событий, заказов → объём на единицу бизнес-метрики (например, 2 КБ на заказ × 100k заказов в месяц = 200 МБ/мес + индексы ×2).
- Прогноз: через 6/12/24 месяцев.
- Порог действий: «при 70% диска — расширяем; при 85% — авария».
predict_linear(node_filesystem_avail_bytes{mountpoint="/var/lib/postgresql"}[7d], 30 * 24 * 3600) < 0Контроль роста: партиционирование и удаление старых данных, архивация (S3, ClickHouse), TTL, сжатие (TOAST, lz4), очистка bloat, удаление неиспользуемых индексов.
Пик нагрузки и запас
- проектируйте под пиковые значения (p95/p99 недели/месяца), не под средние;
- запас (headroom): CPU 30–40%, диск 30%, память; до 70% нормальной загрузки;
- N+1 отказоустойчивость: при потере узла оставшиеся выдерживают нагрузку;
- разовые события (маркетинг, релиз, миграция, бэкап, отчёты) учитывайте отдельно.
Нагрузочное тестирование
pgbench(стандартные и свои сценарии), k6, JMeter, Gatling, воспроизведение реального трафика (pgreplay, pg_stat_statements);- тесты на данных продового размера и распределения;
- измеряйте: TPS, p95/p99 latency, CPU, iowait, hit ratio, лаг репликации, при растущей нагрузке — точку насыщения;
- сценарии: пик, долгая устойчивая нагрузка (soak), скачок (spike), отказ узла (chaos).
pgbench -i -s 1000 app # инициализация, масштаб 1000 (≈15 ГБ)
pgbench -c 64 -j 8 -T 600 -P 10 app # 64 клиента, 8 потоков, 10 минутСпособы масштабирования
| Способ | Когда | Комментарий |
|---|---|---|
| Оптимизация запросов и индексов | всегда первым | дешевле любого железа |
| Вертикальное (scale up) | быстро, просто | предел и цена, возможен простой |
| Read replicas | высокая доля чтения | лаг, маршрутизация |
| Кэш (Redis), CQRS | повторяющиеся чтения | инвалидация |
| Пул соединений | много клиентов | PgBouncer |
| Партиционирование, архивация | большие таблицы | |
| Аналитика вынести (ClickHouse) | тяжёлые отчёты | CDC |
| Шардирование | запись и объём за пределами одного узла | сложность |
Стоимость (FinOps)
Тип инстанса, диски и IOPS, реплики, бэкапы и хранение, межзональный трафик, лицензии. Правила: удалить неиспользуемое, архивировать, резервировать мощности (reserved/savings plans) для стабильных нагрузок, автоскейлинг реплик (где поддерживается), отдельные контуры dev/stage меньшего размера.
Процесс
- ежемесячный/ежеквартальный обзор ёмкости (capacity review) с отчётом: текущее использование, прогноз, риски, рекомендации;
- дашборд ёмкости и алерты по прогнозу;
- привязка к бизнес-планам (запуск новых функций, рост пользователей);
- документ «пределы системы»: известные узкие места и порог перехода на следующую архитектуру.
Вопросы с ответами
Как спрогнозировать, когда закончится диск?
Собрать историю размеров, построить тренд (линейный или по бизнес-метрике), учесть сезонность и WAL/бэкапы/bloat, задать порог действий (например 70%) и алерт по
predict_linear.
Почему «больше соединений» не значит «быстрее»?
Каждое соединение — процесс с памятью; при числе активных сессий выше числа ядер растут очереди и переключения контекста. Оптимально ограничивать серверные соединения пулом (PgBouncer).
С чего начинать масштабирование?
С измерений и оптимизации запросов и индексов, затем кэш, реплики, партиционирование/архивация, вынесение аналитики; вертикальное масштабирование и шардирование — следующие шаги по необходимости.