Ответ
Шардирование (горизонтальное партиционирование) — это метод распределения строк одной таблицы по нескольким базам данных (шардам) на разных серверах.
Основные цели:
- Масштабирование записи и чтения: Нагрузка распределяется между несколькими узлами.
- Увеличение производительности: Каждый шард содержит подмножество данных, что уменьшает размер индексов и ускоряет запросы.
- Повышение доступности: Отказ одного шарда не останавливает всю систему.
Типичные стратегии шардирования:
- По диапазону (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).