Базы данных
Шардинг: горизонтальное масштабирование записи
В 2010 году у Twitter была проблема: 400 миллионов твитов в день не помещались на один MySQL сервер. Инженеры создали Gizzard - систему шардинга MySQL. Сейчас YouTube обрабатывает 500 часов видео в минуту через Vitess - тот же MySQL, но с шардингом на 100,000+ серверов.
- **Shopify**: Vitess для MySQL шардинга - 1 млн+ магазинов, пики в Black Friday без downtime
- **Instagram**: 10,000+ PostgreSQL шардов для хранения данных 2 млрд пользователей
- **Uber**: 1000+ PostgreSQL шардов для trip history, геолокаций, pricing данных
Зачем нужен шардинг
Вертикальное масштабирование (добавить CPU/RAM) имеет предел. Самый мощный сервер AWS (x2iedn.32xlarge) стоит $26/час и имеет 4TB RAM. Когда данные не помещаются - нужен шардинг: разбить данные на несколько серверов (shards). Каждый shard = независимая БД, хранит подмножество данных.
Шардинг - последнее средство оптимизации. Сначала: индексы, caching, read replicas, вертикальное масштабирование. Шардинг добавляет огромную сложность: нет JOIN между шардами, нет глобальных транзакций, resharding болезненен.
Когда шардинг необходим?
Hash vs Range шардинг
Hash шардинг: shard = hash(key) % N. Равномерное распределение данных, нет hot shards. Минус: range queries требуют обращения ко всем шардам (scatter-gather). Range шардинг: shard по диапазону значений (A-M на shard1, N-Z на shard2). Range queries эффективны, но возможны hot shards (все новые записи с timestamp на последний шард).
| Параметр | Hash Sharding | Range Sharding |
|---|---|---|
| Распределение данных | Равномерное | Может быть неравномерным |
| Range queries | Scatter-gather (все шарды) | Эффективно (один шард) |
| Hot shards | Маловероятны | Риск при монотонном key |
| Используется в | Cassandra, MongoDB | HBase, DynamoDB (при range key) |
Consistent hashing - улучшение hash шардинга: при добавлении нового шарда перемещается только 1/N данных, а не полный resharding. Используется в Cassandra, Amazon DynamoDB, Memcached. Узлы образуют кольцо, данные переходят только к ближайшему новому соседу.
Система хранит временные ряды с timestamp как ключом. Какой шардинг выбрать?
Проектирование Shard Key
Shard key - самое важное архитектурное решение при шардинге. Изменить его потом = полный resharding = часы даунтайма или сложная online migration. Критерии хорошего shard key: высокая cardinality (много уникальных значений), равномерное распределение, соответствует access patterns (связанные данные на одном шарде).
Instagram shard approach: logical_shard_id = user_id % 2000, physical_shard = mapping[logical_shard_id]. Двухуровневый маппинг: 2000 логических шардов на любое количество физических. Добавить физический сервер = переместить часть логических шардов.
Таблица заказов. Какой shard key выбрать если нужны: "все заказы пользователя" и "все заказы за период"?
Resharding
Resharding - перераспределение данных между шардами при добавлении новых или изменении shard key. Наивный подход: остановить систему, перенести данные, запустить. Это недопустимо для production. Online resharding требует: двойная запись в старый и новый шард, миграция данных в фоне, проверка консистентности, переключение чтения.
Vitess (used by Shopify, GitHub, YouTube) управляет MySQL шардингом: online resharding, query routing, connection pooling. PlanetScale (hosted Vitess) позволяет менять схему без locks, resharding без даунтайма.
При добавлении нового шарда с hash шардингом (user_id % 100 -> % 101) что происходит?
Cross-Shard запросы
Cross-shard query - запрос к данным на нескольких шардах. Пример: "найти топ-10 активных пользователей" - нужно опросить все шарды (scatter), объединить результаты (gather), отсортировать. При 100 шардах - 100 параллельных запросов + merge в application layer.
Распределённые транзакции через шарды (2PC - Two-Phase Commit) возможны, но крайне медленны из-за blocking protocol. Shopify избегает cross-shard транзакций через data modeling: связанные данные на одном шарде (customer + orders на customer_shard).
Шардинг автоматически ускоряет все запросы
Шардинг ускоряет запросы к конкретному шарду (при правильном shard key). Cross-shard queries медленнее, чем в нешардированной БД при небольших данных.
Шардинг добавляет overhead: network hop, scatter-gather, нет JOIN. Выигрыш только при данных, превышающих возможности одного сервера.
Шардинг по user_id. Как эффективно получить "заказы за последние 24 часа по всем пользователям"?
Ключевые идеи
- **Shard key**: самое важное решение - высокая cardinality, равномерность, соответствие access patterns; изменить после = пересоздать всё
- **Hash vs Range**: hash = равномерность, range queries по всем шардам; range = эффективные range queries, риск hot shards
- **Cross-shard queries**: scatter-gather, pre-aggregation, или data modeling избегающий cross-shard joins
Связанные темы
Шардинг строится поверх репликации и требует понимания партиционирования:
- Партиционирование — Партиционирование - шардинг внутри одного сервера; схожие принципы выбора ключа
- Consistent Hashing — Consistent hashing минимизирует resharding при добавлении узлов
- Репликация — Каждый шард обычно имеет собственные replicas для HA
Вопросы для размышления
- Как Instagram выбирала shard key при 10,000+ шардах PostgreSQL? Какие trade-offs они сделали?
- Система e-commerce: таблицы users, orders, products. По какому принципу шардировать каждую?
- Consistent hashing добавляет 1/N данных при новом шарде. Почему это лучше чем 100% при обычном hash % N?