GH GambleHub

Шардинг и репликация баз данных

Шардинг и репликация баз данных

1) Зачем это нужно

Когда вертикальный апгрейд БД упирается в пределы CPU/IO/RAM или один кластер становится SPOF, приходят репликация (для чтений/HA) и шардинг (для распределения записи/данных). Цели:
  • Пропускная способность (горизонтальный рост write QPS).
  • Доступность (быстрый failover, отсутствие единой точки отказа).
  • Локализация данных (мульти-регион, низкая латентность).
  • Изоляция шумных соседей (hot tenants / hot keys).

2) Базовые термины и модели согласованности

Primary/Leader ↔ Replica/Follower: запись на лидере, чтение — на репликах.
Синхронная репликация: подтверждение транзакции после записи на N узлах (низкий RPO, выше латентность).
Асинхронная: лидер фиксирует коммит и отправляет лог позже (RPO>0, низкая латентность).
Кворумная (Raft/Paxos): запись на большинство узлов; один лог, автоматический лидер.
Read-after-write: гарантированное чтение своих записей (см. §5).

CAP в проде читаем так: при сетевых проблемах вы выбираете согласованность (CP) или доступность (AP) для критичных операций, часто комбинируя уровни на разных путях.


3) Репликация: варианты и практики

3.1 Физическая и логическая

Физическая (WAL/redo/binlog): ближе к блочному журналу, проста и быстра; ограничена гомогенной топологией/версией.
Логическая: поток DML/DDL на уровне строк/таблиц; позволяет частичные реплики, миграции между версиями, CDC для DWH/стриминга.

3.2 Настройка и управление

Контролируйте lag (время/байты/LSN).
Ограничьте hot-standby feedback и долгие запросы на репликах (чтобы не стопорить VACUUM/клининг).
Для MySQL — GTID и Orchestrator; для PostgreSQL — Patroni/replication slots, synchronous_standby_names.

PostgreSQL (синхронная реплика, фрагмент):
sql
-- на лидере
ALTER SYSTEM SET synchronous_commit = 'on';
ALTER SYSTEM SET synchronous_standby_names = 'FIRST 1 (standby_a, standby_b)';
SELECT pg_reload_conf();
MySQL GTID (идентификатор транзакции):
sql
SET GLOBAL enforce_gtid_consistency = ON;
SET GLOBAL gtid_mode = ON; -- перезапуск
CHANGE MASTER TO MASTER_AUTO_POSITION=1;

3.3 Топологии

1→N (лидер → реплики) + каскады (реплика сливает дальше).
Multi-primary (active-active) — избегать в OLTP без строгого конфликт-менеджмента.
Quorum-кластер (Raft) — CockroachDB/Yugabyte/PG-Raft-надстройки.


4) Read/Write Split и маршрутизация

Пишите всегда в лидер; читайте с реплик, но учитывайте lag.

Стратегии read-after-write:

1. Session stickiness: после успешной записи клиент читает с лидера в течение `ΔT`.

2. LSN/GTID-гейт: клиент сообщает «хочу не старее LSN=X», роутер отправляет на реплику, чей LSN ≥ X.

3. Stale-ok: часть запросов допускает устаревшие данные (каталоги/ленты).

Инструменты: PgBouncer/ Pgpool-II (Postgres), ProxySQL/MaxScale (MySQL), Vitess (маршрутизация шардов).

Пример LSN-гейта (идея): сохраняйте `pg_current_wal_lsn()` в HTTP-хедер/куку и требуйте от роутера реплику с `pg_last_wal_replay_lsn() ≥ LSN`.


5) Стратегии шардинга

5.1 Выбор ключа

Ключ должен обеспечивать равномерность и локальность запросов:
  • Hash по `tenant_id`/`user_id` — равномерно, но лишает range-сканов.
  • Range по времени/ID — отлично для time-series/архива, но риск hot-shard.
  • Consistent hashing — упрощает добавление/удаление шардов.
  • Directory/lookup-таблица — гибко (любой алгоритм), но еще одна таблица/кэш.

5.2 Паттерны

Shared-nothing: каждый шард — отдельная БД/кластер, приложение знает маршрутизацию.
Middleware-шардинг: Vitess (MySQL), Citus (Postgres), Proxy-уровень прячет топологию.
Федерация: разделение доменов данных по сервисам (catalog, payments, auth).

5.3 Композитные ключи

Используйте ключ-пространство: `{tenant}:{entity}:{id}` и храните это же в приложении и кэше. Для Postgres — hash partitioning + LIST/RANGE subpartition.

PostgreSQL partitioning (фрагмент):
sql
CREATE TABLE orders (
tenant_id int,
id     bigint,
created_at timestamptz,
...,
PRIMARY KEY (tenant_id, id)
) PARTITION BY HASH (tenant_id);

CREATE TABLE orders_t0 PARTITION OF orders FOR VALUES WITH (MODULUS 16, REMAINDER 0);
--... t1..t15

6) Генерация идентификаторов

Избегайте «горячих» монотонных автоинкрементов на шардинге.
Используйте Snowflake-подобные 64-бит ID (time + region + shard + seq) или ULID/KSUID (монотонность и распределенность).
Для Postgres — sequence per shard; для MySQL — auto_increment_increment/offset (разные оффсеты на лидерах шардов).


7) Онлайн-перешардирование и миграции

Ключевые принципы: двойная запись (dual-write), идемпотентность, временная двойная маршрутизация.

Шаги (обобщенно):

1. Добавьте новый шард/кластер.

2. Включите dual-read (проверка консистентности).

3. Включите dual-write (в оба шарда), фиксируйте расхождения.

4. Выполните backfill исторических данных (батчи, репликация логическая/CDC).

5. Переключите «источник правды» на новый шард; оставьте «хвостовую» синхронизацию.

6. Выключите старый.

Инструменты: Vitess Resharding, Citus move shards, pg_logical/pgoutput, Debezium (CDC), gh-ost/pt-online-schema-change (DDL без блокировок).


8) Мульти-регион и геораспределение

Leader-follower per region: локальные чтения, запись — через глобальный лидер (простая модель, но cross-region RTT).
Multi-leader: запись в обоих регионах — нужен конфликт-мерджинг (timestamp/версия/CRDT).
True distributed SQL (Raft): CockroachDB/Yugabyte — данные «приклеены» к региону, запросы идут в локальный кворум.

Рекомендации:
  • Деньги/заказы — CP (кворум/лидер), каталоги/ленты — AP (кэш, eventual).
  • Всегда планируйте write fencing (уникальные ключи/версионирование) при возможном split-brain.

9) Согласованность на практике

Read-your-writes: лидеру или реплике, «догнавшей» LSN/GTID.
Monotonic reads: «не старше» последнего прочитанного LSN.
Write-conflict control: `SELECT... FOR UPDATE`, версии (`xmin`/`rowversion`), UPSERT с проверкой версии.
Идемпотентность: ключи идемпотентности на оплатах/событиях.


10) Наблюдаемость, SLO и алерты

Лаг реплик: время (сек), LSN distance (bytes), seconds_behind_master (MySQL).
Вынужденные откаты/конфликты, ошибки репликации.
p95/p99 latency по route (read leader vs replica, write).
Throughput: TPS/locks/row-contended tables.
Bloat/VACUUM (PG), InnoDB buffer pool hit ratio (MySQL).
Дашборды: per-shard нагрузка, «горячие» шарды, распределение ключей.


11) Бэкапы, PITR и DR

Полный бэкап + WAL/binlog для PITR (point-in-time recovery).
Храните в другом регионе/облаке, регулярно делайте restore-тесты.
Для шардов — согласованный «срез» (координация времени/LSN) или аппликативная идемпотентность при восстановлении.
RPO/RTO прописаны и тестируются на game-days.

PostgreSQL base backup (идея):
bash pg_basebackup -D /backups/base -X stream -C -S slot_replica_1 архивация WAL через archive_command или pgBackRest/Barman

12) Безопасность и доступ

Сегментация по VPC/ACL, mTLS на прокси.
Роли/гранты по принципу минимальных прав; отдельные пользователи на шард/роль.
Аудит DDL/DCL, лимиты на «тяжелые» запросы на репликах.
Шифрование at rest (KMS) и в транзите (TLS).
«Паника-кнопка»: глобальный `READ ONLY` на время инцидента/расследования.


13) Инструменты и кирпичики

PostgreSQL: Patroni (HA), PgBouncer (pooling/RO-routing), repmgr, pgBackRest/Barman (бэкап), Citus (шардинг), pglogical/Logical Replication, pgbadger/pg_stat_statements.
MySQL: Orchestrator (топологии/авто-failover), ProxySQL/MaxScale (маршрутизация), Percona XtraBackup (бэкап), Group Replication/InnoDB Cluster, Vitess (шардинг/ресхардинг).
Distributed SQL: CockroachDB, YugabyteDB (кворум, встроенный шардинг/геолокация).
CDC: Debezium + Kafka/Pulsar для событий/ETL.


14) Анти-паттерны

Single-primary без авто-failover и без тестов DR.
«Магический» read-split без учета lag → фантомные ошибки/подозрительные баги.
Шардинг «ради шардинга»: преждевременное усложнение вместо вертикального скейла/индексов/кэша.
Горячий диапазон (time-range) без time-bucket/hash-salt → один шард плавится.
Глобальная транзакция 2PC поверх десятков шардов в OLTP — высокие хвосты p99 и частые блокировки.
Отсутствие dual-write/dual-read при миграциях → потеря/рассинхрон.
DDL в проде без онлайн-инструментов и без фиче-флагов совместимости.


15) Чек-лист внедрения (0–60 дней)

0–15 дней

Определить SLO БД, RPO/RTO.
Включить репликацию, мониторинг lag, базовые бэкапы + PITR.
Ввести роутер (PgBouncer/ProxySQL) и политику read-after-write.

16–30 дней

Выбрать стратегию шардинга, описать ключи и схемы.
Подготовить инструменты перешардирования (Vitess/Citus/CDC).
Каталог сервисов/таблиц с пометкой «read-stale-ok» vs «strict».

31–60 дней

Запустить pilot-шард, dual-read и backfill.
Game-day: failover лидера, восстановление из PITR, переключение региона.
Автоматизировать отчеты по горячим шард-ключам и неравномерности.


16) Метрики зрелости

Replica lag p95 < целевого (например, 500 ms) для критичных чтений.
Успешные DR-тесты ≥ 1/квартал (restore ≤ RTO, потеря ≤ RPO).
Распределение нагрузки по шардам: дисбаланс < 20% по QPS/хранилищу.
Доля запросов со strict-consistency, корректно маршрутизированная, = 100%.
Zero-data-loss в инцидентах, требующих CP-гарантий (деньги/заказы).
Онлайн DDL/миграции без простоев, с флагами совместимости.


17) Примеры рецептов

Hash-salt для time-range (чтобы не греть один шард):
sql
-- вычисляйте bucket = hash(user_id) % 16, храните (bucket, created_at)
PARTITION BY LIST (bucket) SUBPARTITION BY RANGE (created_at)
Read-my-writes middleware (псевдокод):
python lsn = db.leader_query("SELECT pg_current_wal_lsn()")
ctx.sticky_until = now()+5s ctx.min_lsn = lsn в роутере чтений: выбираем реплику с last_lsn >= ctx.min_lsn, иначе лидер
Vitess VSchema (фрагмент):
json
{
"tables": {
"orders": { "column_vindexes": [{ "column": "tenant_id", "name": "hash" }] }
}
}

18) Заключение

Шардинг и репликация — это не только техника, но и процессы: маршрутизация с учетом согласованности, дисциплина миграций (dual-write/read, backfill), регулярные DR-тесты и наблюдаемость lag/горячих шардов. Начинайте с простого leader→replica + read-after-write, затем добавляйте шардинг там, где его действительно требует профиль нагрузки. Используйте готовые платформы (Vitess/Citus/Distributed SQL) и держите бизнес-критичные данные в CP-режиме — так база перестанет быть бутылочным горлышком и станет предсказуемым, эластичным фундаментом платформы.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.