Что такое шардирование?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Шардирование: Горизонтальное Масштабирование Базы Данных
Шардирование (Sharding) — это техника горизонтального масштабирования, при которой данные распределяются между несколькими независимыми базами данных (шардами) на основе значения ключа шардирования. Каждый шард содержит подмножество данных и может работать независимо на отдельном сервере.
Основной Принцип
Вместо одной большой базы данных, ты разбиваешь данные на несколько меньших баз, где каждая отвечает за определённый диапазон значений ключа.
ОД большая БД: Шардированная система:
┌──────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 1M records │ → │ Shard 0 │ │ Shard 1 │ │ Shard 2 │
│ (slow) │ │ 333k rec │ │ 333k rec │ │ 333k rec │
└──────────────┘ └──────────┘ └──────────┘ └──────────┘
Стратегии Шардирования
1. Range-Based (Диапазонное) Шардирование
def get_shard_by_range(user_id, num_shards=4):
"""
Разделяет пользователей по диапазонам ID
"""
# User ID 1-250k → Shard 0
# User ID 250k-500k → Shard 1
# User ID 500k-750k → Shard 2
# User ID 750k-1M → Shard 3
range_size = 1_000_000 // num_shards
shard_id = user_id // range_size
return min(shard_id, num_shards - 1)
print(get_shard_by_range(100_000)) # Shard 0
print(get_shard_by_range(400_000)) # Shard 1
print(get_shard_by_range(800_000)) # Shard 3
Преимущества: Просто реализовать, легко находить диапазон Недостатки: Может быть несбалансированное распределение если ID неполные
2. Hash-Based (Хеш) Шардирование
import hashlib
def get_shard_by_hash(user_id, num_shards=4):
"""
Использует хеш для равномерного распределения
"""
hash_value = int(hashlib.md5(str(user_id).encode()).hexdigest(), 16)
return hash_value % num_shards
print(get_shard_by_hash("user-001")) # Shard 2
print(get_shard_by_hash("user-002")) # Shard 0
print(get_shard_by_hash("user-003")) # Shard 3
Преимущества: Хорошее распределение, масштабируемость Недостатки: Сложнее обработать добавление новых шардов (rehashing)
3. Directory-Based (На основе таблицы маршрутизации)
# Таблица маршрутизации
SHARD_MAPPING = {
'user-001': 0,
'user-002': 1,
'user-003': 2,
'user-004': 3,
# ...
}
def get_shard_directory(user_id):
return SHARD_MAPPING.get(user_id)
Преимущества: Максимальная гибкость, легко переехать данные Недостатки: Требует отдельное хранилище маршрутизации
Реализация Шардирования
На Уровне Приложения (Application-Level Sharding)
from sqlalchemy import create_engine
class ShardedDatabase:
def __init__(self, shard_configs):
# shard_configs = {
# 0: 'postgresql://localhost/db_shard_0',
# 1: 'postgresql://localhost/db_shard_1',
# 2: 'postgresql://localhost/db_shard_2',
# }
self.engines = {
shard_id: create_engine(config)
for shard_id, config in shard_configs.items()
}
def _get_shard_id(self, user_id):
return hash(user_id) % len(self.engines)
def get_user(self, user_id):
shard_id = self._get_shard_id(user_id)
engine = self.engines[shard_id]
with engine.connect() as conn:
result = conn.execute(
f"SELECT * FROM users WHERE id = {user_id}"
)
return result.fetchone()
def create_user(self, user_id, name, email):
shard_id = self._get_shard_id(user_id)
engine = self.engines[shard_id]
with engine.connect() as conn:
conn.execute(
f"INSERT INTO users (id, name, email) VALUES ({user_id}, '{name}', '{email}')"
)
conn.commit()
# Использование
db_shards = {
0: 'postgresql://localhost/db_shard_0',
1: 'postgresql://localhost/db_shard_1',
2: 'postgresql://localhost/db_shard_2',
}
db = ShardedDatabase(db_shards)
db.create_user('user-001', 'Alice', 'alice@example.com') # → Shard 0
db.get_user('user-001') # Обращение к Shard 0
На Уровне БД с Отдельными Таблицами
-- Создание шарда 0
CREATE TABLE users_shard_0 (
user_id UUID PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255),
created_at TIMESTAMP
);
-- Создание шарда 1
CREATE TABLE users_shard_1 (
user_id UUID PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255),
created_at TIMESTAMP
);
-- Представление для прозрачного доступа
CREATE VIEW users AS
SELECT * FROM users_shard_0
UNION ALL
SELECT * FROM users_shard_1;
Распределённые Системы Шардирования
Для Production используют специализированные решения:
- MySQL Proxy / Vitess — Разработан Google, используется в large-scale systems
# Vitess автоматически маршрутизирует запросы
VTGATE_HOST = 'vitess-gateway.example.com'
connection = mysql.connector.connect(
host=VTGATE_HOST,
user='root',
database='keyspace:shard'
)
- PostgreSQL с Citus — Native шардирование в PostgreSQL
SELECT * from create_distributed_table('users', 'user_id');
- MongoDB Sharding — Встроенное шардирование
sh.shardCollection("mydb.users", { "user_id": "hashed" })
Проблемы и Решения
Проблема: Горячие Шарды (Hot Shards)
Если один шард получает много больше нагрузки:
# Решение: Compound Shard Key
def get_shard_compound(user_id, timestamp):
# Вместо только user_id используем комбинацию
key = f"{user_id}_{timestamp}"
return hash(key) % num_shards
Проблема: JOIN Между Шардами
def cross_shard_query(user_ids):
"""
Запрос к нескольким шардам одновременно
"""
results = {}
shard_map = {}
# Группируем user_ids по шардам
for user_id in user_ids:
shard_id = get_shard_id(user_id)
if shard_id not in shard_map:
shard_map[shard_id] = []
shard_map[shard_id].append(user_id)
# Запрашиваем каждый шард отдельно
for shard_id, ids in shard_map.items():
engine = self.engines[shard_id]
result = engine.execute(f"SELECT * FROM users WHERE id IN {tuple(ids)}")
results.update(result)
return results
Проблема: Resharding (Добавление нового шарда)
Это сложная операция, требует переезда данных:
def add_new_shard():
# 1. Создать новый шард
# 2. Скопировать данные из существующих шардов
# 3. Обновить функцию хеширования
# 4. Постепенно переводить трафик на новый шард
# 5. Удалить старые данные после валидации
pass
Когда Использовать Шардирование
✅ База данных > 500 GB ✅ > 10,000 QPS ✅ Данные неограниченно растут ✅ Одна таблица > 1 млрд строк ✅ Нужно масштабировать writes
Когда НЕ Использовать
❌ База < 100 GB ❌ Нужны частые cross-shard операции ❌ Много аналитических запросов ❌ Можно использовать read replicas
Альтернативы
- Vertical Scaling — Больше памяти/CPU для одного сервера
- Read Replicas — Масштабирование чтения
- Caching Layer — Redis, Memcached
- Data Warehouse — Snowflake, BigQuery для аналитики
Шардирование — это последний шаг оптимизации, когда другие методы исчерпаны. Используй только когда действительно нужно.