# Шардирование

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

Источник: https://llmdocs.ru/wiki/sharding/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Суть**: разные строки — на разных серверах
- **Отличие от репликации**: репликация копирует данные, шардирование делит
- **Стратегии**: по диапазону, по хешу, по справочнику (directory), географическое
- **Ключевое решение**: выбор ключа шардирования
- **Решения для PostgreSQL**: Citus, партиционирование + FDW
- **Решения для MySQL**: Vitess, ProxySQL
- **Встроенное**: MongoDB, Cassandra, CockroachDB, YDB, ClickHouse
**Шардирование** (англ. *sharding*) — способ горизонтального масштабирования базы данных, при котором строки одной логической таблицы распределяются между несколькими независимыми серверами — **шардами**. Каждый шард хранит только часть данных и обслуживает только запросы к ней. Шардирование позволяет выйти за пределы одной машины по объёму данных и, главное, по нагрузке на запись — но делает систему заметно сложнее.[1]

## Шардирование, репликация и партиционирование

Эти понятия часто путают:

- **[Репликация](https://llmdocs.ru/wiki/replication.md)** хранит *копии одних и тех же* данных на нескольких серверах. Она повышает доступность и масштабирует чтение, но каждая реплика должна принимать все записи.
- **Партиционирование** делит таблицу на части *внутри одного сервера* (например, по месяцам) — в [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) это декларативное партиционирование.[6] Оно упрощает удаление старых данных и ускоряет запросы, но не добавляет ресурсов.
- **Шардирование** — это партиционирование *между серверами*. На практике его сочетают с репликацией: у каждого шарда есть свои реплики.

Прежде чем шардировать, обычно исчерпывают более простые средства: вертикальное масштабирование (больше процессоров, памяти, быстрые диски), [индексы](https://llmdocs.ru/wiki/database-index.md) и оптимизацию запросов, реплики для чтения, [кэширование](https://llmdocs.ru/wiki/cache.md), архивирование старых данных. Современный сервер с терабайтами NVMe и сотнями ядер выдерживает очень многое.

## Ключ шардирования

Каждая строка попадает на шард в зависимости от значения **ключа шардирования** — одного или нескольких столбцов. Выбор ключа — самое важное и труднообратимое решение:[2]

- **высокая кардинальность** — много различных значений, чтобы данные можно было распределить;
- **равномерность** — без «горячих» значений, иначе один шард будет перегружен (например, ключ по стране, когда 80 % пользователей из одной страны);
- **локальность запросов** — большинство запросов должны затрагивать один шард. Для SaaS-приложений естественный ключ — `tenant_id` (идентификатор клиента-организации): все данные клиента лежат вместе, а [транзакции](https://llmdocs.ru/wiki/transaction-acid.md) и соединения остаются локальными.

## Стратегии распределения

| Стратегия | Как работает | Плюсы | Минусы |
|---|---|---|---|
| По диапазону | `id 1–1 млн → шард 1`, `1–2 млн → шард 2` | эффективные запросы по диапазону | «горячий» последний шард при монотонных ключах |
| По хешу | `hash(key) mod N` | равномерное распределение | запросы по диапазону идут на все шарды |
| По справочнику | таблица «ключ → шард» | гибкость, ручной перенос клиентов | справочник — отдельная точка отказа |
| Географическая | данные региона — в регионе | задержки, требования законов о локализации | неравномерность нагрузки |

Наивное `hash(key) mod N` плохо переносит изменение числа шардов: при переходе с 4 на 5 почти все ключи меняют шард. Поэтому используют **согласованное хеширование** (consistent hashing),[5] при котором при добавлении узла переезжает лишь ~1/N данных, — как в Amazon Dynamo и Cassandra,[7] — или заранее создают много **виртуальных шардов** (например, 1024), которые затем распределяют и перемещают между физическими серверами целиком.

## Маршрутизация запросов

Кто-то должен знать, куда отправить запрос:

- **само приложение** — библиотека вычисляет шард по ключу;
- **прокси или координатор** — Vitess (vtgate) для MySQL,[3] координатор Citus для PostgreSQL, mongos в MongoDB;[4]
- **встроенная распределённая СУБД** — CockroachDB, YugabyteDB, YDB, TiDB, Cassandra, [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md) сами шардируют и перемещают данные, предоставляя единый SQL-интерфейс.

## Сложности

- **Запросы между шардами** (*scatter-gather*) — запрос без ключа шардирования рассылается на все шарды, а результаты собираются и сортируются координатором. Медленно и дорого.
- **Соединения (JOIN)** между данными на разных шардах. Решения — совместное размещение (co-location) связанных таблиц по одному ключу, дублирование небольших справочных таблиц на все шарды.
- **Распределённые транзакции** требуют двухфазной фиксации и медленнее локальных; многие системы их ограничивают.
- **Уникальность и идентификаторы** — автоинкремент не работает глобально; используют UUID (лучше UUIDv7), Snowflake-подобные ID или диапазоны на шард.
- **Перебалансировка** — перенос данных при добавлении шарда без простоя и с согласованностью.
- **Эксплуатация** — резервное копирование, миграции схемы, мониторинг умножаются на число шардов.

Эти компромиссы — частный случай общих проблем [распределённых систем](https://llmdocs.ru/wiki/distributed-systems.md) (см. [CAP-теорема](https://llmdocs.ru/wiki/cap-theorem.md)).

## Пример: Citus

```sql
CREATE EXTENSION citus;
CREATE TABLE events (tenant_id bigint, id bigserial, payload jsonb,
                     PRIMARY KEY (tenant_id, id));
SELECT create_distributed_table('events', 'tenant_id');   -- шардирование по клиенту
SELECT create_reference_table('countries');               -- копия на каждом узле
```

После этого запросы с `WHERE tenant_id = 42` идут на один узел, а агрегаты по всем клиентам выполняются параллельно на всех.

## См. также

- [Репликация баз данных](https://llmdocs.ru/wiki/replication.md)
- [Распределённые системы](https://llmdocs.ru/wiki/distributed-systems.md)
- [MongoDB](https://llmdocs.ru/wiki/mongodb.md)
- [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md)

## Источники

1. [Kleppmann — Designing Data-Intensive Applications, ch. 6 Partitioning (O'Reilly)](https://dataintensive.net/)
2. [Citus documentation — Choosing the distribution column](https://docs.citusdata.com/en/stable/sharding/data_modeling.html)
3. [Vitess documentation — Sharding](https://vitess.io/docs/reference/features/sharding/)
4. [MongoDB Manual — Sharding](https://www.mongodb.com/docs/manual/sharding/)
5. [Karger et al. — Consistent Hashing and Random Trees (STOC 1997)](https://doi.org/10.1145/258533.258660)
6. [PostgreSQL — Table Partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html)
7. [DeCandia et al. — Dynamo: Amazon's Highly Available Key-value Store (SOSP 2007)](https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf)
