Что такое шардирование в распределенных системах?

«Что такое шардирование в распределенных системах?» — вопрос из категории Распределенные системы, который задают на 33% собеседований Data Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Зачем это нужно:

  • Масштабирование записи и чтения: Нагрузка распределяется между узлами.
  • Увеличение доступности: Отказ одного шарда не приводит к падению всей системы.
  • Географическое распределение: Данные можно размещать ближе к пользователям.

Ключевые концепции:

  1. Ключ шардирования: Определяет, на какой шард попадут данные (например, user_id, tenant_id).
  2. Стратегии шардирования:
    • Диапазонное: Данные распределяются по диапазонам ключа (например, A-M на шард 1, N-Z на шард 2). Может привести к дисбалансу ("горячие" шарды).
    • Хэш-шардирование: Ключ хэшируется, и хэш определяет шард. Обеспечивает равномерное распределение, но усложняет запросы по диапазонам.
    • Шардирование по справочнику: Используется отдельная lookup-таблица для сопоставления ключа и шарда. Гибко, но требует поддержки отдельного сервиса.

Проблемы и решения:

  • Запросы, затрагивающие несколько шардов (fan-out): Требуют агрегации результатов от всех шардов, что медленно. Решение — дублирование данных или использование материализованных представлений.
  • Решардинг (перераспределение данных): Необходим при добавлении/удалении шардов. Сложная операция, требующая миграции данных без простоя. Современные системы (например, Vitess, CockroachDB) делают это прозрачно.
  • Транзакции, затрагивающие несколько шардов: Реализуются через протоколы распределенного консенсуса (например, 2PC, Raft), что влияет на производительность.

Пример (концептуальный): База пользователей шардирована по user_id на 3 узла с использованием хэша.

-- Определение шарда для пользователя с id=123
shard_index = hash(123) % 3  -- Например, результат = 1
-- Запрос направляется на шард 1
SELECT * FROM users WHERE user_id = 123 ON shard_1;