Предел размера базы для одного сервера: на каком терабайте пора шардировать
Рано или поздно у растущей базы данных возникает вопрос: сколько ещё можно расти на одном сервере, прежде чем всё начнёт разваливаться. Ответ «столько-то терабайт» — упрощение, которое почти всегда вводит в заблуждение: одна база спокойно живёт на 10 ТБ, а другая начинает тормозить уже на 500 ГБ. Дело не в абсолютном объёме на диске, а в том, как он соотносится с памятью, паттерном записи и требованиями к простою. Разберём, что физически упирается в потолок на одном сервере, как оценить именно свой предел и какие есть более дешёвые варианты, прежде чем браться за шардирование.
Содержание
Что на самом деле упирается в потолок
Диск почти никогда не первопричина проблемы — современные NVMe-накопители по объёму спокойно берут десятки терабайт в одном сервере. Упирается не место на диске, а три других ресурса, которые растут вместе с базой куда болезненнее.
Первое — память под рабочий набор. База быстро работает не потому, что диск быстрый, а потому, что часто используемые страницы данных и индексов лежат в буферном кэше в RAM. Пока «горячая» часть данных помещается в память, задержки предсказуемые. Как только рабочий набор перерастает RAM, запросы начинают регулярно упираться в диск, и даже на NVMe это на порядок медленнее обращения к памяти — подробнее в разборе буферного пула базы данных. Индексы особенно чувствительны: B-деревом можно быстро найти строку, только если верхние уровни дерева и активные листья кэшируются в памяти — если индекс весит 300 ГБ, а под кэш индексов выделено 32 ГБ, часть обращений неизбежно уходит на диск.
Второе — обслуживание (maintenance), которое проходит по всей таблице целиком: VACUUM в PostgreSQL, OPTIMIZE TABLE в MySQL, пересборка индекса, ANALYZE. Его время растёт вместе с объёмом таблицы, а не с объёмом «полезных» изменений в ней. Вакуум таблицы на 50 ГБ и на 5 ТБ — принципиально разные по длительности операции, даже при одинаковом проценте мёртвых строк.
Третье — время восстановления из бэкапа (RTO). Логический дамп pg_dump/pg_restore на объёме в несколько терабайт может идти много часов, и это время равно простою бизнеса при аварии. Физические бэкапы (pgBackRest, XtraBackup, ZFS-снапшоты) восстанавливаются быстрее логических, но тоже упираются в скорость диска и сети. Здесь важно считать не «сколько весит бэкап», а именно время простоя — этому посвящена статья про то, что реально считать при восстановлении.
Спрашивать «на каком терабайте пора шардировать» бессмысленно без ответа, сколько из этого объёма — горячие данные, как часто идёт обслуживание и какой у вас допустимый простой при восстановлении.
Признаки, что вы уже уперлись в предел одного сервера
Прежде чем оценивать абстрактный предел, посмотрите на конкретные симптомы — они появляются раньше, чем «кончается место».
- Рабочий набор перестал влезать в кэш. В PostgreSQL посмотрите на отношение попаданий в кэш к промахам:
SELECT
sum(heap_blks_hit) / nullif(sum(heap_blks_hit) + sum(heap_blks_read), 0) AS cache_hit_ratio
FROM pg_statio_user_tables;
Если это отношение стабильно ниже 0.95-0.99 на активных таблицах и продолжает снижаться по мере роста данных — рабочий набор обгоняет память.
- Автовакуум/OPTIMIZE не успевает. Проверьте разрыв между «мёртвыми» и «живыми» строками и время последнего вакуума:
SELECT relname, n_dead_tup, n_live_tup, last_autovacuum, last_vacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC LIMIT 15;
Если по крупным таблицам n_dead_tup растёт быстрее, чем вакуум успевает его сокращать, а last_autovacuum регулярно «отстаёт» на часы — обслуживание не поспевает за нагрузкой. Частые причины и настройки разобраны в статье про медленный VACUUM в PostgreSQL.
- Окно обслуживания растянулось за пределы допустимого простоя. Если раньше ночной REINDEX или полный VACUUM укладывался в час, а теперь занимает шесть — это сигнал, что объём таблицы перерос возможности сервера обслуживать её в разумное время.
- RTO вырос за пределы SLA. Замерьте реальное время восстановления тестовым прогоном на копии, а не «на глаз» по размеру бэкапа. Если восстановление занимает 8 часов, а бизнес требует вернуться в строй за 2 — это уже вопрос архитектуры хранения, а не настройки бэкапа.
- Индекс не помещается в память целиком. Если
EXPLAIN (ANALYZE, BUFFERS)стабильно показываетBuffers: shared read=...(а не толькоhit) на точечных запросах по индексированному полю — часть индекса регулярно читается с диска.
Если у вас нет ни одного из этих симптомов, а объём просто «звучит внушительно» — вы ещё далеко от реального предела, независимо от того, сколько терабайт на диске.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверКак оценить свой предел, а не искать чужую цифру
Универсального числа терабайт не существует, потому что предел определяется не объёмом на диске, а отношением между объёмом, паттерном доступа и железом. Вот на что смотреть.
Соотношение горячих и холодных данных. У склада логов почти все данные «холодные» — читаются редко, большими последовательными сканами. У биллинга активного SaaS горячие обычно только записи за последние недели, а годами накопленный архив почти не трогают. Оцените долю данных, к которой реально идут запросы за типичный рабочий день:
SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS total_size,
seq_scan, idx_scan
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC LIMIT 20;
Если 80% объёма — данные старше года, к которым запросы почти не идут, ваш реальный «рабочий» объём в разы меньше цифры на диске, и вертикального масштабирования хватит надолго.
Соотношение рабочего набора и доступной памяти. Прикидка грубая, но рабочая: сложите объём индексов и часто читаемых частей таблиц, сравните с объёмом RAM, реально выделяемым под кэш (shared_buffers в PostgreSQL, innodb_buffer_pool_size в MySQL — обычно 60-75% RAM сервера). Если рабочий набор кратно больше доступной памяти и разрыв продолжает расти вместе с бизнесом — вертикальное масштабирование скоро упрётся в потолок, который предлагает рынок серверов.
Скорость роста и время обслуживания. Посчитайте не текущий объём, а темп прироста в месяц и то, как от него зависит время VACUUM/REINDEX. Если maintenance растёт линейно с объёмом (а часто это так), экстраполируйте: через сколько месяцев окно обслуживания превысит допустимый простой.
Требования к RTO и RPO. Часто самый жёсткий и недооценённый предел. Если бизнес требует восстановления за час, а физика диска и сети даёт час на каждые условные несколько сотен гигабайт данных — предел определяется требованием к простою при аварии, и он может наступить раньше, чем начнут «тормозить запросы».
Ни одна из этих метрик по отдельности не даёт готового ответа — но вместе они дают именно вашу оценку, а не усреднённую чужую.
Вертикальное масштабирование: докуда реально можно расти
Прежде чем шардировать, стоит выжать вертикальный рост — часто он закрывает вопрос на годы вперёд дешевле и без архитектурной сложности. Применительно к базам данных — вот основные рычаги.
Память — первый и самый эффективный рычаг. Увеличение RAM напрямую увеличивает объём рабочего набора, который помещается в кэш, и часто снимает проблему без единой строчки изменений в схеме. Конкретные объёмы памяти, доступные в одном сервере, зависят от платформы и линейки процессоров на момент заказа — уточняйте их у поставщика под свою задачу, а не ориентируйтесь на цифры из старых статей.
NVMe и распределение I/O. Если рабочий набор физически не помещается в память (аналитика, полнотекстовый поиск по большому архиву), важна не столько ёмкость диска, сколько его пропускная способность — вынос WAL/логов транзакций на отдельный NVMe-том, разделение табличных пространств по разным дискам.
Настройка планировщика вместо железа. Часть проблем «база не тянет объём» на деле — не упор в железо, а игнорируемые индексы и устаревшая статистика планировщика. Проверьте это до апгрейда — стоимость диагностики на порядок ниже стоимости нового сервера.
Практический ориентир: если после апгрейда памяти и вынесения логов на отдельный NVMe рабочий набор снова помещается в кэш с запасом — вы купили себе год-два роста без перехода к распределённой архитектуре. Если он продолжает расти быстрее, чем можно нарастить память на доступном классе серверов, — вертикальный запас на исходе, дальше нужно либо сокращать сам рабочий набор архивацией, либо переходить к горизонтальному масштабированию.
Партиционирование и архивация вместо шардирования
Прежде чем разносить данные по разным серверам, почти всегда стоит разнести их по разным партициям на том же сервере или вынести неактивную часть за пределы основной базы. Это решает большинство симптомов из второго раздела без сетевых задержек и распределённых транзакций, которые приносит шардирование.
Партиционирование по диапазону (чаще всего по дате) делит одну огромную таблицу на несколько физических кусков внутри одной базы:
CREATE TABLE events (
id bigint,
created_at timestamptz NOT NULL,
payload jsonb
) PARTITION BY RANGE (created_at);
CREATE TABLE events_2026_08 PARTITION OF events
FOR VALUES FROM ('2026-08-01') TO ('2026-09-01');
Это даёт три выигрыша сразу. Во-первых, VACUUM и ANALYZE работают по отдельным партициям — партиция за прошлый месяц, в которую больше не пишут, вакуумится один раз и дальше почти не трогается. Во-вторых, запросы с условием по дате физически сканируют только нужные партиции (partition pruning). В-третьих, старые партиции можно целиком выгружать или удалять командой DROP TABLE вместо медленного построчного DELETE — это мгновенная операция вместо часов работы и раздувания WAL.
Вынос архивных данных за пределы горячей базы — второй по эффективности шаг. Если 80% объёма — записи старше полугода-года, к которым обращаются редко, их можно перенести в отдельное холодное хранилище: сервер подешевле, объектное хранилище с выборочной выгрузкой, отдельную базу только для отчётов. Горячая база при этом резко худеет, рабочий набор снова помещается в память, а обслуживание — в окно. Обращение к архиву можно организовать через FDW (foreign data wrapper) в PostgreSQL или отдельный сервис для редких исторических запросов — быстрота здесь не критична, важна доступность данных при необходимости.
Индексация под фактический паттерн запросов — менее очевидный, но заметный по эффекту шаг: частичные индексы (WHERE status = 'active'), покрывающие индексы под конкретные запросы, удаление неиспользуемых индексов. Если раньше не оценивали реальную стоимость своих индексов, стоит начать с этого, прежде чем добавлять железо.
Комбинация «партиционирование + архивация + точечная индексация» в большинстве случаев отодвигает потребность в шардировании на годы, а иногда закрывает вопрос полностью — особенно если рост базы объясняется накоплением истории, а не ростом активной нагрузки.
Когда шардирование действительно необходимо
Шардирование — не следующая по порядку ступень после вертикального масштабирования, а качественно другое архитектурное решение с постоянной сложностью в обмен на снятое ограничение по железу. Прежде чем к нему переходить, стоит честно проверить, что альтернативы из предыдущих разделов исчерпаны, а не просто не опробованы. Что такое шардирование, чем оно отличается от партиционирования и репликации и как выбрать ключ — разобрано подробно в статье «Шардирование базы данных: основы». Здесь — именно про признаки, что оно нужно именно вам.
Шардирование оправдано, когда одновременно верно несколько условий:
- Вертикальный рост упёрся в потолок доступного железа, а не просто «дороговато» — даже максимальная конфигурация памяти и дисков на рынке не даёт рабочему набору поместиться в кэш с запасом.
- Партиционирование и архивация уже применены, но горячих данных всё равно больше, чем помещается на один сервер — проблема не в накопленной истории, а в объёме активной части.
- Нагрузка на запись упирается в возможности одного сервера, а не только чтение — каждая запись всё равно идёт через один WAL/binlog, и партиционирование здесь не помогает.
- Есть естественный ключ шардирования — данные делятся на независимые группы (клиенты, регионы, тенанты в multi-tenant SaaS) почти без JOIN-ов и распределённых транзакций между ними. Без такого ключа шардирование превращается в постоянную борьбу с межшардовыми запросами.
- Команда готова нести операционную сложность постоянно: мониторинг нескольких серверов, перераспределение данных при неравномерном росте шардов, отсутствие единой ACID-транзакции на всю систему, более сложные бэкапы.
Если хотя бы одно из первых трёх условий не выполнено — вероятно, вертикальный рост или партиционирование решат проблему дешевле и без постоянной нагрузки на команду. Шардирование стоит выбирать как осознанное решение под измеренный предел, а не страховку «на будущее» — сложность оно приносит сразу, а выгоду только когда предел одного сервера реально достигнут.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Есть ли универсальная цифра в терабайтах, после которой пора шардировать?
Нет, любая конкретная цифра из обсуждений отражает чужой паттерн нагрузки, а не ваш. Сервер с холодным архивом живёт с объёмом в десятки терабайт, а база с горячим рабочим набором может упереться в предел памяти уже на сотнях гигабайт. Ориентируйтесь на симптомы, а не на абсолютный объём.
Партиционирование — это уже шардирование?
Нет. Партиционирование делит таблицу на части ради удобства обслуживания и скорости запросов, но все партиции остаются на одном сервере с общим CPU, RAM и диском. Шардирование физически разносит данные по разным серверам с независимыми ресурсами — и добавляет сетевые задержки и распределённую сложность.
Может ли апгрейд памяти решить проблему без смены архитектуры?
Часто да, если проблема именно в том, что рабочий набор не помещается в кэш. Проверьте отношение попаданий в кэш до и после апгрейда на тестовом окружении — это дешевле, чем сразу проектировать шардированную схему.
Что делать, если естественного ключа шардирования нет?
Это сигнал, что шардирование пока рано обсуждать всерьёз. Без ключа, делящего данные на независимые группы без межшардовых JOIN-ов, любая схема шардирования превращается в источник постоянных проблем. Сначала стоит поработать над архитектурой данных или закрыть вопрос вертикальным ростом и архивацией.
Как проверить, что бэкап действительно восстановится за приемлемое время?
Единственный надёжный способ — регулярный тестовый прогон восстановления на отдельном сервере с замером реального времени, а не оценка по размеру дампа. Разница между теоретической и фактической скоростью восстановления на большом объёме бывает в разы.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →