Шардирование PostgreSQL: где распределение данных ломается
Шардирование PostgreSQL может снять нагрузку с одного узла, но добавляет новые точки отказа: горячие шарды, дорогие запросы без ключа распределения и сложное перемещение данных. Разбираем риски на примере PostgreSQL 16.

В PostgreSQL 16 запрос по ключу шарда может попасть на один сервер, а запрос отчёта без этого ключа — разойтись по всем узлам и собрать результаты обратно. Так масштабирование превращает простой SQL в распределённую операцию: растут задержки, усложняются транзакции и становится дороже обслуживание. Ниже — подводные камни, которые важно проверить до переноса данных.
Сначала отделите партиции от шардов
Встроенное декларативное партиционирование PostgreSQL делит таблицу на части, но само по себе не распределяет их по разным серверам. Партиции остаются внутри одного кластера PostgreSQL. Это полезно для управления большими таблицами и отсечения ненужных данных при запросе, но не добавляет горизонтального масштабирования между узлами.
Шардинг — распределение строк между отдельными узлами по выбранному ключу. Его можно реализовать в приложении или с помощью распределённого расширения. У этих вариантов разные гарантии и ограничения: не стоит считать, что расширение автоматически превращает любой SQL и любую транзакцию в операцию над единой базой.
Термин. Ключ шардирования — поле или набор полей, по которым система определяет, на каком узле хранить строку. Если ключом служит идентификатор клиента, данные одного клиента можно держать вместе, но равномерность распределения зависит от того, как распределены сами клиенты.
Цена ключа, который кажется очевидным
Ключ определяет не только место хранения. Он влияет на то, можно ли выполнить запрос на одном узле, как соединять таблицы и получится ли равномерно распределить нагрузку. Хороший ключ совпадает с частыми фильтрами и связями в запросах. Плохой заставляет систему регулярно обращаться ко всем шардам или перегружает один из них.
Например, распределение заказов по customer_id удобно, если приложение чаще читает историю конкретного клиента. Но крупный клиент с несравнимо большим объёмом заказов может стать горячим шардом. Распределение по дате может помочь запросам за отдельный период, но текущий месяц способен получить почти всю запись, пока старые шарды простаивают.
- Соберите реальные запросы. Проверьте, какие фильтры встречаются в чтении и записи, какие поля используются в JOIN и сколько запросов приходят без предполагаемого ключа.
- Посмотрите на перекос данных. Сравните будущие объёмы и частоту операций по значениям ключа, а не только общее число строк.
- Проверьте запросы «по всей системе». Поиск, отчёт или административная операция без ключа распределения могут потребовать опроса нескольких узлов и объединения результатов.
До миграции полезно смоделировать распределение на копии данных и прогнать профиль реальных запросов. Измеряйте не только среднее время, но и хвост задержек, количество задействованных узлов, объём переданных между ними данных и разницу нагрузки между самым загруженным и наименее загруженным шардом. Универсальной цифры, после которой шардинг становится выгоден, нет: результат зависит от запросов, объёма данных и оборудования.
Шардирование ускоряет не базу вообще, а только те операции, которые удаётся направить на нужный узел. Остальным оно добавляет сетевую работу.
Глобальная целостность перестаёт быть бесплатной
В одном экземпляре базы PostgreSQL проверяет ограничения и выполняет транзакции в рамках доступной ей структуры данных. После распределения часть проверок может потребовать координации между узлами — или перестать поддерживаться выбранным способом шардирования. Это нужно выяснить до проектирования схемы, а не после того, как приложение начало создавать записи.
Уникальность и внешние ключи
Если идентификатор уникален только внутри шарда, два узла могут выдать одинаковое значение. Приложению понадобится стратегия глобально уникальных идентификаторов или распределения диапазонов. У каждой стратегии своя цена: отдельная координация, ограничения на создание записей либо необходимость учитывать возможные коллизии.
Внешний ключ между строками на разных узлах также нельзя считать автоматически защищённым так же, как внешний ключ в одной обычной таблице. Конкретные возможности зависят от реализации. Если приложение проверяет связь самостоятельно, возможна гонка: одна операция проверила существование родительской записи, а другая удалила её до завершения записи.
Отдельная тонкость есть и у обычного партиционирования PostgreSQL 16: уникальное ограничение на секционированной таблице должно включать все столбцы ключа секционирования. Это не правило для любого вида шардинга, а ограничение встроенного партиционирования; при проектировании схемы важно не смешивать эти механизмы.
Транзакции и повтор операций
Если одна бизнес-операция затрагивает несколько шардов, ей требуется согласовать изменения на нескольких узлах. Это сложнее, чем транзакция на одном сервере: отказ или задержка одного участника влияет на всю операцию. Поддержка распределённых транзакций зависит от конкретного решения, его настроек и версии. Не закладывайте привычную атомарность без проверки документации.
В распределённой системе также важна повторяемость запросов после таймаута. Клиент может не знать, успел ли сервер зафиксировать запись. Если он повторит запрос, операция способна выполниться дважды. Идемпотентность — возможность повторить операцию без повторного эффекта — нужно проектировать для критичных записей отдельно.
Перенос данных — отдельный проект
После добавления узлов данные не распределятся «бесплатно». Их нужно переместить, пока приложение продолжает обслуживать запросы, и при этом не потерять записи, возникшие во время переноса. Конкретный механизм зависит от выбранной архитектуры, но план должен описывать порядок копирования, переключения чтения и записи, проверку полноты данных и возврат назад при ошибке.
Перераспределение может перегрузить сеть и диски, конкурировать с рабочими запросами и временно увеличить задержки. Поэтому оценивайте не только длительность копирования на тесте, но и влияние на рабочую нагрузку. Если ключ шардирования пришлось менять, операция часто сложнее обычного добавления сервера: затрагивается само соответствие строки и узла.
Что выбирать: партиции, приложение или расширение
| Подход | Когда уместен | Цена и ограничение |
|---|---|---|
| Партиционирование PostgreSQL 16 | Большая таблица, которую нужно делить по диапазону или списку значений внутри одного кластера | Не распределяет данные по серверам; схема ограничений и ключей требует внимания |
| Шардинг в приложении | Команда готова явно маршрутизировать запросы и контролировать операции между узлами | Логика распределения, поиск без ключа, миграции и целостность ложатся на приложение |
| Распределённое расширение | Нужны инструменты для распределения данных и команда готова работать в рамках возможностей конкретного решения | Поддержка SQL, транзакций, DDL и отказоустойчивости зависит от расширения и его версии; появляется отдельный слой эксплуатации |
Выбирайте партиционирование, если проблема в управлении крупными таблицами на одном сервере, а не в необходимости распределить нагрузку. Шардинг в приложении подходит, когда ключ маршрутизации очевиден для большинства запросов и команда готова владеть распределённой логикой. Расширение стоит оценивать по конкретному списку запросов и операций: проверьте ограничения на JOIN, транзакции, индексы, резервное копирование и обновление версии.
Где подход ломается первым
Типичные сигналы, что схема распределения не совпала с нагрузкой, — один постоянно перегруженный узел, запросы, которые затрагивают почти все шарды, и операции записи, которым приходится ждать координации. Ещё один тревожный признак — разработчики не могут назвать, какой узел обслужит конкретный запрос и что произойдёт, если он станет недоступен.
Перед запуском проверьте сценарии, которые часто остаются за пределами успешного демо:
- один ключ создаёт непропорционально много записей или запросов;
- клиент выполняет поиск или отчёт без ключа шардирования;
- бизнес-операция меняет связанные данные на разных узлах;
- нужно добавить узел, переместить часть данных или восстановить только один сегмент;
- таймаут случается после отправки записи, но до ответа клиенту.
Для каждого сценария определите, кто принимает решение, какие данные сверяются после сбоя и сколько времени система может работать с неполными результатами. Проверяйте поведение на нагрузочном тесте и учениях по восстановлению, а не только по плану на бумаге.
Что делать дальше
Начните не с выбора расширения, а с карты запросов и данных: выпишите ключевые чтения и записи, укажите, где находится ключ шардирования, и отметьте операции, пересекающие его границы. Затем измерьте перекос будущего распределения и прогоните тест на копии данных. Для PostgreSQL 16 отдельно сверьте правила встроенного партиционирования с документацией. К проектированию миграции переходите только после того, как понятны поведение при отказе узла и цена запросов без ключа.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: PostgreSQL 16: декларативное партиционирование, PostgreSQL 16: ограничения и внешние ключи
Частые вопросы
Партиционирование PostgreSQL — это уже шардирование?
Можно ли выбрать ключ шардирования по главному идентификатору таблицы?
Что будет с запросами, в которых нет ключа шардирования?
Можно ли сохранить внешние ключи и транзакции между шардами?
Что если у меня не PostgreSQL 16?
Как понять, что шардинг действительно помог?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.