Распределённые системы
Репликация данных
Цели урока
- Объяснить три причины репликации и когда каждая актуальна
- Описать Leader-Follower модель и trade-off синхронной vs асинхронной репликации
- Понять проблему конфликтов в Multi-Leader и основные стратегии разрешения
- Рассчитать кворумы W/R/N для Leaderless системы под заданные требования
Предварительные знания
- Понимание CAP-теоремы и eventual consistency
- Базовые знания о транзакциях и WAL (Write-Ahead Log)
- Знакомство с концепцией distributed failure modes
GitHub, октябрь 2018: 24 секунды сетевого сбоя рассинхронизировали MySQL-реплики и привели к 5 часам деградации. Выбор модели репликации - это выбор между скоростью, консистентностью и сложностью конфликтов.
- **PostgreSQL streaming replication** - Leader-Follower с synchronous_commit=remote_apply для финансовых данных (нет потерь при failover)
- **Cassandra QUORUM** - Leaderless W=2, R=2, N=3 в Netflix для пользовательских настроек и очередей
- **Google Docs** - Multi-Leader с CRDT-based conflict resolution, позволяет offline-редактирование и concurrent editing
- **CouchDB** - Multi-Leader для мобильных приложений, конфликты резолвятся через user-visible revision tree
- **DynamoDB Global Tables** - Multi-Leader across AWS регионов, LWW по умолчанию с опцией custom conflict resolution
Amazon Dynamo и рождение NoSQL
В 2007 году Amazon опубликовал статью 'Dynamo: Amazon's Highly Available Key-value Store'. Инженеры описали систему без единого leader - кворумы, consistent hashing, vector clocks, hinted handoff. Статья стала манифестом NoSQL движения. Cassandra, Riak, DynamoDB - все реализовали идеи Dynamo. Один из авторов, DeCandia, позже описал как команда убедила скептиков: 'мы не можем позволить одному datacenter-outage остановить корзину покупателя'.
Зачем реплицировать данные
**GitHub, 28 октября 2018. В 22:52 UTC сетевой инженер меняет оборудование в одном дата-центре - трафик кратковременно перебрасывается через Азию. За 24 секунды сети MySQL master-replica рассинхронизируются. Итог: 4 минуты полного outage и 5 часов работы в деградированном режиме.** Репликация данных - это не просто копирование, это архитектурное решение о том, где хранится истина и как она расходится по узлам.
Три причины, по которым системы реплицируют данные, несводимы друг к другу.
| Цель | Что даёт | Пример |
|---|---|---|
| Отказоустойчивость | При падении узла данные доступны на других репликах | PostgreSQL streaming replication: primary упал, standby принимает запросы за секунды |
| Низкая задержка | Чтение с географически близкого узла вместо cross-region запроса | Netflix: 13 регионов AWS, видео читается из ближайшего (p50 < 20 мс вместо 200+ мс) |
| Масштабирование чтения | Нагрузка распределяется по репликам - горизонтальный scale без шардирования | Instagram использовал PostgreSQL + 20 read replicas до перехода на Cassandra |
**Ключевая сложность репликации** - не копирование данных, а управление изменениями. Каждая запись должна прийти на все реплики в корректном порядке. Если реплика отстала на 1 секунду - за это время могут прийти тысячи транзакций. Что делать с конфликтами? В каком порядке применять? Это и определяет выбор модели репликации.
Реплика - это то же самое, что backup
Реплика - живая копия, синхронизируемая в реальном времени. Backup - snapshot прошлого состояния.
Если выполнить DROP TABLE или массовый DELETE - операция реплицируется на все реплики мгновенно. Backup не затронут. Поэтому репликация не заменяет backup strategy.
Система читает данные в 10 раз чаще, чем пишет. Какая основная цель репликации в этом случае?
Leader-Follower: единственный источник правды
Leader-Follower (Master-Replica) - самая распространённая модель репликации. Один узел-лидер принимает все записи. Follower-узлы получают копию через replication log и обслуживают запросы на чтение.
Синхронная vs асинхронная репликация
| Режим | Задержка записи | Гарантия | Применение |
|---|---|---|---|
| Синхронная | Высокая (+RTT до follower) | Follower подтверждает - данные точно есть на 2+ узлах | PostgreSQL synchronous_commit=on, финансовые данные |
| Асинхронная | Низкая (только локальная запись) | Eventual - follower обновится когда-нибудь | MySQL default, метрики, логи, не критичные данные |
| Полусинхронная | Средняя | Хотя бы 1 follower подтвердил | MySQL semi-sync - компромисс durability vs latency |
**Replication lag** - отставание follower от лидера. При асинхронной репликации клиент может прочитать устаревшие данные с реплики. PostgreSQL показывает lag через `pg_stat_replication.replay_lag`. Типичное значение: 10-100 мс в нормальных условиях, секунды - при перегрузке сети или диска.
Синхронная репликация всегда лучше - надёжнее
Синхронная репликация увеличивает latency каждой записи на RTT до follower и блокирует при недоступности follower
PostgreSQL с synchronous_commit=on ждёт подтверждения от всех синхронных standbys. Если один из них временно недоступен - все записи ждут. Поэтому компромисс: хотя бы один синхронный standby (а не все) плюс асинхронные остальные.
Primary падает при асинхронной репликации. Follower успел применить 990 из 1000 транзакций. Что происходит при failover?
Multi-Leader: несколько источников правды
Multi-Leader (Active-Active) - несколько узлов принимают записи. Каждый лидер реплицирует свои изменения на остальных. Главное преимущество - запись в ближайший датацентр без cross-region roundtrip. Главная проблема - **конфликты записи**.
Конфликт записи в multi-leader
DC West получает запрос: `user.name = "Alice"`. DC East одновременно получает: `user.name = "Bob"`. Оба лидера применяют запись локально и отправляют реплику друг другу. Через 80 мс (RTT между US регионами) оба обнаруживают конфликт. Чья версия побеждает?
| Стратегия | Как работает | Проблема |
|---|---|---|
| Last Write Wins (LWW) | Побеждает запись с большим timestamp | Клоки не синхронизированы - NTP погрешность 10+ мс. Cassandra использует LWW по умолчанию |
| First Write Wins | Побеждает первая запись, последующие отклоняются | Требует координации для определения 'первой' - теряет преимущество multi-leader |
| Merge / CRDT | Значения объединяются по логике типа данных | Работает для счётчиков, множеств, но не для произвольных строк |
| Application logic | Конфликт передаётся на уровень приложения для разрешения | Сложно реализовать корректно, но максимально гибко |
**Где multi-leader применяется:** CouchDB (offline-first sync), Google Docs (CRDT-based), PlanetScale (Vitess multi-region), GitLab Geo (geo-replication). Не применять для финансовых данных и случаев где конфликты неразрешимы без потерь.
CouchDB используется для мобильного приложения с offline-режимом. Пользователь редактирует документ офлайн, синхронизируется позже. Какая стратегия конфликтов подходит лучше?
Leaderless: кворумы вместо лидера
**Amazon Dynamo, 2007 - статья изменила индустрию.** Werner Vogels и команда описали систему без единого leader: клиент пишет сразу на N узлов, запись считается успешной при подтверждении W из них. Чтение с R узлов берёт самую свежую версию. DynamoDB, Cassandra, Riak - все выросли из этой идеи. Условие гарантированной консистентности: W + R > N.
| Узел | Действие | Результат |
|---|---|---|
| Node 1 | Получает запрос на запись | ACK |
| Node 2 | Получает запрос на запись | ACK |
| Node 3 | Недоступен | Запись не дошла |
| Итог | Кворум W=2 достигнут (2 из 3 ACK) | Запись успешна |
| Конфигурация W/R/N | Свойство | Используется для |
|---|---|---|
| W=1, R=N | Быстрая запись, медленное чтение | Write-heavy системы, логи |
| W=N, R=1 | Медленная запись, быстрое чтение | Read-heavy с жёсткой консистентностью |
| W=2, R=2, N=3 | Баланс - 1 узел может упасть | Cassandra по умолчанию (QUORUM) |
| W=1, R=1 | Максимальная скорость, нет гарантий | Eventual consistency, кеши |
**Sloppy quorum** - при недоступности нужных реплик Dynamo-style системы пишут на любые W доступных узлов, даже не ответственных за этот ключ. После восстановления - hinted handoff: данные передаются на правильные узлы. Cassandra делает это по умолчанию.
W + R > N гарантирует strong consistency как в RDBMS
W + R > N гарантирует что хотя бы один узел с последней версией участвует в чтении, но не атомарность и не изоляцию
Leaderless системы не поддерживают транзакции между ключами по умолчанию. Два concurrent write на разные реплики могут создать конфликт. W+R>N - необходимое, но недостаточное условие для strong consistency.
Cassandra кластер: N=5, W=3, R=3. Падают 2 узла. Система продолжает принимать записи?
Вопросы для размышления
- Рассмотри сервис, которым пользуешься ежедневно (мессенджер, банковское приложение, облачное хранилище). Какую модель репликации он скорее всего использует и почему этот выбор обоснован для конкретного use case?
Связанные уроки
- ds-08-vector-clocks — Multi-master replication needs vector clocks for conflicts
- ds-10-crdts — CRDT-based replication is a coordination-free strategy
- dist-12-consistency — Replication lag directly limits achievable consistency level
- db-13-transactions