Распределённые системы
Репликация данных
Цели урока
- Объяснять разницу между репликацией и backup и почему одно не заменяет другое
- Сравнивать Leader-Follower, Multi-Leader и Leaderless по latency, consistency и сложности
- Рассчитывать кворумные конфигурации N/W/R для заданных требований
- Выбирать стратегию разрешения конфликтов для конкретного use case
Предварительные знания
- CAP-теорема: понимание trade-off между consistency и availability
- Базовое понимание сетевых задержек и partition tolerance
- Знакомство с транзакциями и ACID-гарантиями
GitLab потерял 300 ГБ production-данных за 5 минут. Backup существовал, но не восстанавливался - никто не проверял. Репликация - не magic bullet, а целая дисциплина с trade-off на каждом шагу.
- **PostgreSQL streaming replication** - стандарт для highload: primary + 2 hot standby, failover за секунды через Patroni или repmgr
- **Amazon DynamoDB** - leaderless с tunable consistency: по умолчанию eventual, за дополнительные 2x latency - strongly consistent reads
- **Cassandra в Netflix** - RF=3 с LOCAL_QUORUM: пережили целый AWS region outage без downtime благодаря multi-DC replication
- **Google Spanner** - синхронная репликация через Paxos с TrueTime API: strong consistency глобально ценой 7-14 мс commit wait
- **MySQL semi-sync в Facebook** - при падении лидера гарантировано не более одной потерянной транзакции (одна реплика всегда подтвердила)
Amazon Dynamo и рождение NoSQL
В 2007 Amazon опубликовал Dynamo paper - систему которая управляла корзиной покупок на пике нагрузки в Black Friday. Ключевое решение: отказаться от single leader ради availability. Конфликты разрешает сам клиент (application-level). Эта статья запустила волну NoSQL баз: Cassandra (Facebook, 2008), Riak, Voldemort. Идеи кворумов и consistent hashing из Dynamo используются в каждой современной distributed БД.
Зачем хранить одно в трёх местах
**GitLab, 31 января 2017. 23:23 UTC. Инженер удалил 300 гигабайт production-базы - ошибочный rsync в не ту сторону. Backup-скрипты не работали уже 6 месяцев - никто не проверял. В итоге потеряно 5 000 проектов и 6 часов downtime.** Причина не в ненадёжном железе - причина в единственной копии данных.
**Репликация** - хранение идентичных копий данных на нескольких независимых узлах. Три цели: отказоустойчивость (узел упал - данные живы), низкая задержка (читай с ближайшего узла), масштабирование чтения (10 реплик = 10x read throughput).
| Система | Реплик | Что получают |
|---|---|---|
| Amazon S3 | 3+ в одном регионе, 3+ регионов | 11 nines durability - потеря файла вероятнее выигрыша в лотерею |
| PostgreSQL streaming | 1 primary + N standby | Failover за секунды, read scaling через hot standby |
| Cassandra | RF=3 по умолчанию | Пережить падение целого дата-центра без потери данных |
| Kafka | replication.factor=3 | Потребитель продолжает читать при отказе брокера |
Главная сложность репликации - не хранение копий, а **синхронизация изменений**. Клиент записал на Leader в DC West. Как и когда это оказывается на Follower в DC East? Выбор стратегии определяет всё: latency, consistency, что происходит при сетевом разрыве.
Репликация = backup. Есть 3 реплики - данные в безопасности
Репликация и backup - разные вещи. Реплики хранят текущее состояние и тоже получат DELETE или коррупцию. Backup - отдельная копия в point-in-time.
Если выполнить DROP TABLE, все 3 реплики применят эту операцию через секунды. Репликация защищает от отказа железа, но не от ошибки оператора или бага в коде. Для защиты от обоих нужны и реплики, и point-in-time backup в отдельном хранилище.
GitLab потерял production-данные несмотря на то, что backup-скрипты были настроены. Какой принцип репликации был нарушен?
Leader-Follower: один пишет, все читают
**Самая распространённая модель:** один узел (Leader, Primary, Master) принимает все записи. Остальные (Followers, Replicas, Standby) получают изменения через replication log и отвечают на запросы чтения. PostgreSQL, MySQL, MongoDB replica set, Redis Sentinel - все работают по этой схеме.
Синхронная vs Асинхронная репликация
| Режим | Latency записи | Гарантия | Потеря при failover | Пример |
|---|---|---|---|---|
| Синхронная | Высокая (+roundtrip до реплики) | Strong: follower подтвердил до ACK клиенту | 0 транзакций | PostgreSQL synchronous_commit=on |
| Асинхронная | Низкая (локальный commit) | Eventual: реплика отстаёт на N операций | До нескольких секунд данных | MySQL async, Redis AOF async |
| Полусинхронная | Средняя | 1 реплика подтвердила до ACK | Минимальная | MySQL semi-sync, PostgreSQL remote_apply |
**Replication lag** - фундаментальная проблема асинхронной репликации. Клиент записал на leader, сразу читает с follower - видит старое значение. Решения: sticky sessions (читай с той же реплики что писал), read-your-writes consistency (читай с leader свои последние записи), мониторинг lag через `pg_stat_replication.write_lag`.
PostgreSQL настроен с асинхронной репликацией. Leader принял транзакцию и упал через 200 мс. Что произойдёт с данными?
Multi-Leader и конфликты: когда один лидер - узкое место
**Проблема single leader:** все записи идут через один узел. Если дата-центры в Токио, Дублине и Вирджинии - пользователь из Токио ждёт roundtrip до Вирджинии на каждую запись (170+ мс). Multi-Leader решает это: каждый DC имеет свой leader, клиент пишет в ближайший.
Конфликты: неизбежная цена Multi-Leader
Классический write conflict
DC West: user.name = "Alice" (timestamp 10:00:00.100). DC East: user.name = "Bob" (timestamp 10:00:00.150). Оба DC применили запись локально. Когда реплики синхронизируются - у кого данные правильные? Timestamp не помогает: часы разных серверов расходятся на десятки миллисекунд.
| Стратегия разрешения | Механизм | Когда применять |
|---|---|---|
| Last Write Wins (LWW) | Побеждает запись с наибольшим timestamp | Cassandra по умолчанию. Простота ценой возможной потери данных |
| First Write Wins | Первая запись побеждает, повторные отклоняются | Регистрация уникального username - важна первая |
| Merge / CRDT | Значения объединяются по правилам типа данных | Счётчики, наборы (sets), документы в Google Docs |
| Custom application logic | Конфликт передаётся в бизнес-логику | Shopping cart (Amazon Dynamo), документы с историей |
**Практика:** Multi-Leader редко используется внутри одного DC - там single leader быстрее и проще. Основное применение - geographic distribution (несколько регионов), offline clients (Google Docs, CouchDB - каждый клиент является лидером пока offline), collaborative editing.
Multi-Leader = лучше чем Single Leader - больше лидеров, больше пропускная способность
Multi-Leader добавляет сложность конфликтов. Подходит только для geographic distribution или offline clients.
В рамках одного дата-центра Single Leader проще и даёт предсказуемую consistency. Multi-Leader нужен когда latency до единственного leader неприемлема (>50 мс межрегиональный roundtrip) или когда система должна работать offline.
Google Docs позволяет двум пользователям редактировать один документ одновременно без блокировок. Какой подход к конфликтам используется?
Leaderless и кворумы: Amazon Dynamo против традиций
**Amazon, 2007. Werner Vogels публикует Dynamo paper.** Ни одного лидера - клиент пишет одновременно на N узлов и ждёт подтверждения от W из них. При чтении опрашивает R узлов и берёт самое свежее значение. Если W+R>N - гарантировано пересечение: хотя бы один из R узлов видел последнюю запись. На этой идее построены Cassandra, Riak, DynamoDB.
| Узел | Действие | Результат |
|---|---|---|
| Node 1 | Получает запрос на запись | ACK |
| Node 2 | Получает запрос на запись | ACK |
| Node 3 | Недоступен | Запись не дошла |
| Итог | Кворум W=2 достигнут (2 из 3 ACK) | Запись успешна |
**Кворумное уравнение:** N = число реплик, W = кворум записи, R = кворум чтения. Гарантия: при W + R > N хотя бы один узел из R видел последнюю запись. Типичные конфигурации: N=3, W=2, R=2 (баланс); N=3, W=3, R=1 (максимальная durability записи); N=3, W=1, R=3 (максимальная скорость записи).
| Модель | Сильные стороны | Слабые стороны | Примеры |
|---|---|---|---|
| Leader-Follower | Простота, strong consistency, ordering гарантирован | Single point of bottleneck, failover требует election | PostgreSQL, MySQL, MongoDB RS |
| Multi-Leader | Low latency в разных регионах, offline work | Конфликты неизбежны, сложная consistency | CouchDB, Google Docs (OT), Cassandra multi-DC |
| Leaderless | Высокая доступность, нет SPOF, tunable consistency | Eventual consistency, read repair overhead, версионирование | Cassandra, Riak, DynamoDB |
W+R>N гарантирует strong consistency как у одного сервера
W+R>N гарантирует только что хотя бы один из прочитанных узлов видел последнюю запись - но выбор правильного значения требует версионирования.
Если два узла вернули разные версии, нужен механизм определить которая свежее: vector clocks, timestamps (ненадёжны без синхронизации часов), или CRDT-семантика. Без этого W+R>N не спасёт от чтения устаревших данных.
Cassandra настроена N=5, W=3, R=3. Сколько узлов может упасть без потери возможности читать данные?
Вопросы для размышления
- При проектировании системы хранения сессий пользователей (миллион активных, 5 минут TTL) какую модель репликации и кворумную конфигурацию выбрать и почему? Что важнее - не потерять сессию или не задержать ответ?
Связанные уроки
- ds-02-cap-theorem — CAP-теорема ограничивает гарантии репликации
- ds-03-consensus — Консенсус необходим для безопасной синхронной репликации
- ds-04-clocks — Логические часы определяют как измерять replication lag
- dist-07-2pc — 2PC - один из способов сделать репликацию атомарной
- dist-09-raft — Raft реализует репликацию журнала через консенсус
- db-13-transactions