Что такое шардирование базы данных и какие задачи оно решает?

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

Ответ

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

Основные цели:

  1. Масштабирование записи и чтения: Нагрузка распределяется между несколькими узлами.
  2. Увеличение производительности: Каждый шард содержит подмножество данных, что уменьшает размер индексов и ускоряет запросы.
  3. Повышение доступности: Отказ одного шарда не останавливает всю систему.

Типичные стратегии шардирования:

  • По диапазону (Range): Данные делятся по диапазону ключа (например, user_id от 1 до 1M на шард A, от 1M+ на шард B).
  • По хешу (Hash): Ключ шардирования хешируется, результат определяет номер шарда. Обеспечивает равномерное распределение.
  • По списку (List): Явное указание, какие значения ключа попадают на какой шард (например, пользователи из region='EU' на шард 1).

Пример реализации шардирования по хешу на уровне приложения:

public class ShardManager {
    private List<String> shardUrls = List.of(
        "jdbc:mysql://shard01.db/app",
        "jdbc:mysql://shard02.db/app",
        "jdbc:mysql://shard03.db/app"
    );

    // Определяем шард для конкретного userId
    public String getShardUrlForUser(long userId) {
        int shardIndex = Math.abs(Long.hashCode(userId)) % shardUrls.size();
        return shardUrls.get(shardIndex);
    }

    public Connection getConnectionForUser(long userId) throws SQLException {
        String url = getShardUrlForUser(userId);
        return DriverManager.getConnection(url, "user", "pass");
    }
}
// Все данные для пользователя с userId=123 всегда будут на одном и том же шарде.

Недостатки и сложности:

  • Решардинг: Перераспределение данных при добавлении/удалении шардов — сложная операция.
  • Распределенные JOIN: Выполнение JOIN между таблицами на разных шардах неэффективно или невозможно.
  • Распределенные транзакции: Требуют сложных протоколов (2PC, Saga).
  • Сложность запросов: Запросы без ключа шардирования (shard key) должны выполняться на всех шардах (fan-out).