Атлас / РепликацияЭКСПЕРИМЕНТ 01 · ОКОЛО 10 МИНУТ

Репликация
и устаревшие чтения

Успешная запись не означает, что все копии уже обновились. Проследите путь одного значения в небольшой распределённой системе и исследуйте этот разрыв.

Асинхронная репликацияОдин лидерКомпромиссы согласованности
ИНТЕРАКТИВНЫЙ ЭКСПЕРИМЕНТ / 01

Одна запись. Три точки зрения.

Шаг 0

Запишите → прочитайте реплику → выполните два шага → прочитайте снова. Запись создаёт два сообщения; только шаг времени доставляет их.

0 в очереди0 в очередиЛИДЕР · v0HelloРЕПЛИКА A · v0HelloРЕПЛИКА B · v0Hello

Лидер: Hello · v0

Реплика A: Hello · v0 · синхронизирована

Реплика B: Hello · v0 · синхронизирована

Подтверждается сразу. Репликация занимает два шага.
Чтение не продвигает время и не доставляет обновления.
3 / Разрыв связи

Чтений пока нет. Предскажите результат и прочитайте реплику.

В пути 0

FIFO для каждой реплики · доставка через два шага

Нет сообщений в очереди.

Журнал событий

Сначала новые · последние 100 событий

  1. Шаг 0 · Все реплики начинают с v0: «Hello».

Сначала предскажите результат

Все три узла начинают со значения Hello версии 0. Запишите Goodbye, затем прочитайте реплику A, не продвигая время. Какое значение она вернёт?

Она вернёт Hello. Лидер принял версию 1, но на реплике всё ещё версия 0. Выполните два шага и прочитайте снова: теперь A вернёт Goodbye. Вы увидели устаревшее чтение, а затем сходимость.

Причина — задержка репликации

Задержка репликации — это время между принятием записи лидером и появлением этой записи на реплике. Здесь задержка равна двум явным шагам симуляции. В реальной системе на неё влияют сеть, очереди, работа с диском и нагрузка реплики.

Реплика отвечает из применённого ею состояния. Она не узнаёт автоматически, что у лидера есть более новые данные. В этой модели «устаревшее» означает, что возвращённая версия старее версии лидера на момент чтения. Последнее чтение на экране остаётся историческим наблюдением, даже когда время идёт дальше.

Разорвите связь

Сбросьте эксперимент. Заблокируйте реплику B, запишите Goodbye и выполните два шага. A догонит лидера, B — нет. Прочитайте B, затем восстановите связь. Само восстановление ничего не доставляет: выполните ещё один шаг, чтобы применить просроченные обновления.

Теперь сделайте две записи, пока B заблокирована. Её очередь сохранит обе версии. После восстановления они будут применены в порядке записи на следующем шаге. Итоговое значение будет самым новым. В этой модели разрыв связи может увеличивать отставание, не мешая лидеру принимать записи.

Какой компромисс мы выбрали?

Подтверждение записи лидером без ожидания реплик убирает задержку репликации из пути подтверждения. Цена — последующее чтение с реплики может вернуть старую версию, в том числе клиенту, который только что записал данные.

Можно читать с лидера, ждать определённую версию на реплике или вводить гарантии сессии. Каждый вариант имеет свою цену и сценарии отказа. Здесь мы их не моделируем. Гарантии реальных баз данных зависят от продукта, топологии, политики подтверждения, маршрутизации чтений и настроек; само слово «репликация» мало что обещает.

Далее: Чтение собственных записей сравнивает мгновенное чтение с реплики и чтение, ожидающее последнюю подтверждённую запись вашей сессии.

Границы модели

  • Один лидер, две реплики и один строковый ключ. Все начинают с v0.
  • Лидер подтверждает запись сразу. Это не доказывает сохранность данных при сбое.
  • Версии — логические порядковые номера. Шаги — учебные единицы, не миллисекунды.
  • Каждая запись создаёт по сообщению для каждой реплики с доставкой через два шага. Только кнопка Следующий шаг изменяет время.
  • Каждый шаг применяет все сообщения, срок доставки которых наступил, по работающим связям, в порядке FIFO для каждой реплики. Несколько промежуточных значений могут примениться за один шаг.
  • Блокировка затрагивает только репликацию от лидера. Сообщения сохраняются, чтения доступны. Это выборочный разрыв связи, а не полный отказ узла.
  • Нет выборов лидера, его отказов, повторных попыток, потери сообщений, транзакций, параллельных клиентов и постоянного хранения. Перезагрузка сбрасывает состояние; журнал хранит последние 100 событий.
  • Это объясняющая модель, а не бенчмарк базы данных или универсальный контракт согласованности.

Обсудите при проектировании

Изменение профиля подтверждено, но после обновления страницы видно старое имя. Прежде чем добавлять повторные запросы, спросите: где завершилась запись, куда ушло чтение и какая гарантия их связывает?

Источники и дальнейшее чтение

Объяснения, диаграмма и симулятор на этой странице — авторские. Среди источников вдохновения — книга Мартина Клеппмана Designing Data-Intensive Applications (O’Reilly, 2017). Проект независим и не связан с автором или издательством.

Различия конкретных реализаций описаны в официальной документации PostgreSQL: тёплый резерв и асинхронная репликация и MongoDB: причинная согласованность. Эти материалы описывают собственные системы, а не гарантии этой симуляции.