Шардирование и выбор ключа шардирования

↑ 6.1 Масштабирование и надёжность данных · ← Предыдущая · → Следующая

Желательно~4 мин чтенияУровень: senior

Зачем это на собесе

Шардирование — крайняя мера масштабирования записи; нужно знать стоимость и правила выбора ключа.

Что это

Шардирование — горизонтальное разделение данных между независимыми серверами (шардами): каждый хранит подмножество строк. В отличие от партиционирования (внутри одной БД) и репликации (копии одних данных).

Когда нужно

Сначала исчерпайте: оптимизацию запросов и индексов, кэш, read replicas, партиционирование, вертикальное масштабирование, архивацию. Шардирование нужно, когда:

  • запись или объём данных не помещаются на одном сервере;
  • требуется изоляция арендаторов (tenant) или территориальное размещение (data residency).

Цена: сложность, отсутствие JOIN и транзакций между шардами, решардинг, операционные затраты.

Стратегии

СтратегияКакПлюсыМинусы
Range (диапазоны)по диапазонам ключа (даты, id)эффективные range-запросыгорячие шарды (последний диапазон принимает всю запись)
Hashhash(key) mod Nравномерное распределениеrange-запросы по всем шардам; изменение N перемещает почти всё
Consistent hashingкольцо, виртуальные узлыпри смене N переезжает малая долясложнее
Directory / lookupтаблица «ключ → шард»гибкость, ручное размещениеузкое место и сложность справочника
Geoпо региону пользователянизкая задержка, соответствие законамперекосы
Tenant-basedодин арендатор на шардеизоляция, простотанеравномерность (крупные арендаторы)

Выбор ключа шардирования

Критерии хорошего ключа:

  1. Высокая кардинальность и равномерное распределение (нет «горячих» значений);
  2. Соответствие основным запросам: большая часть запросов содержит ключ и попадает на один шард (избегаем scatter-gather);
  3. Отсутствие монотонности при hash-подходе (последовательные id дают перекос при range);
  4. Неизменность: смена значения ключа = перенос строки между шардами;
  5. Данные, которые часто соединяются, хранятся на одном шарде (colocation): customer_id для клиентов, заказов, платежей.

Примеры: tenant_id (SaaS), user_id (пользовательские данные), region. Плохие: created_at (горячий последний шард), низкокардинальный status, country (перекосы).

Проблемы

  • Кросс-шардовые запросы: запрос без ключа идёт на все шарды (scatter-gather), агрегации требуют слияния;
  • Кросс-шардовые транзакции: 2PC или саги; ограничения целостности между шардами не работают;
  • Глобальные уникальные id: Snowflake, UUID v7, ULID, диапазоны выделяются каждому шарду; автоинкремент сломан;
  • Вторичные индексы: локальные (быстро пишутся, но запрос по не-ключу идёт на все шарды) или глобальные (сложнее);
  • Решардинг: перенос данных при росте; нужна онлайн-миграция (двойная запись, бэкфилл, переключение) и заранее заложенные логические шарды (например 256 логических на 4 физических сервера — легко переселять);
  • Горячие ключи (знаменитость, крупный арендатор): дополнительный суффикс, выделенный шард;
  • Справочники реплицируются на все шарды (reference tables).

Реализации

РешениеКомментарий
Citus (расширение PostgreSQL)распределённые таблицы, colocation, reference tables
Vitessшардирование MySQL (YouTube)
CockroachDB, YugabyteDB, TiDB, Spannerраспределённые SQL «из коробки», автоматический решардинг
MongoDB shardingshard key, mongos, балансировщик
Cassandra, ScyllaDB, DynamoDBhash-партиционирование по partition key
Redis Cluster16384 слота
ClickHouse Distributedшардирование таблиц
Application-levelмаршрутизация в коде приложения/прокси

Подход в приложении

public sealed class ShardRouter(IReadOnlyList<string> connectionStrings)
{
    public string For(long tenantId) => connectionStrings[(int)(Hash(tenantId) % connectionStrings.Count)];
}

Лучше — логические шарды и справочник размещения: tenant_id → logical_shard → physical_server, чтобы перенос был сменой записи, а не пересчётом хэша.

Альтернативы шардированию

  • вертикальное масштабирование и оптимизация;
  • партиционирование + холодное хранилище;
  • CQRS: отдельное хранилище для чтения (ClickHouse, Elasticsearch);
  • архивирование старых данных;
  • управляемые распределённые БД.

Вопросы с ответами