Real-Time Backend

Конфликт-резолюция

Два человека одновременно нажали Save. Чьи данные правильные? Ответ на этот вопрос определяет, потеряет ли пользователь свою работу или нет - и это происходит миллионы раз в день в Google Docs, Figma и Notion.

  • **Amazon DynamoDB** использует LWW по умолчанию и рекомендует conditional writes для критичных данных. Неправильно настроенный LWW в production приводил к silent data loss у крупных клиентов
  • **CockroachDB** реализует HLC вместо wall clock для LWW: clock skew до 250ms не влияет на корректность conflict resolution
  • **Notion** при block-level delete vs text-edit конфликте всегда выбирает удаление блока и уведомляет пользователя - это намеренное решение с понятным предсказуемым поведением
  • **Figma** при конфликте свойств объекта использует field-level LWW: цвет и позиция объекта резолвятся независимо, можно потерять только одно свойство, не весь объект

Conflict Strategies

Конфликт в distributed системе - это не ошибка, это штатная ситуация. Два пользователя одновременно изменили одно и то же - кто прав? Ответ зависит от стратегии резолюции. В реальных системах их несколько, и выбор стратегии определяет user experience.

Три фундаментальные стратегии: **Last Write Wins (LWW)** - побеждает последняя запись по timestamp. **First Write Wins (FWW)** - побеждает первый зафиксировавший. **Merge** - оба изменения объединяются в результат, который содержит оба.

**LWW проблема:** wall clock timestamp не надёжен в distributed системах - часы на разных серверах расходятся. Amazon DynamoDB использует LWW по умолчанию и явно предупреждает: если точный порядок важен - используйте conditional writes или версионирование. Cassandra тоже LWW, но с configurable conflict resolution через `TIMESTAMP` колонку.

Два клиента одновременно установили значение поля: A=42 (timestamp=1000ms) и B=99 (timestamp=999ms). LWW с wall clock выберет A. В чём риск этого подхода?

Merge Policies

Merge policy - это правило, как именно объединяются конфликтующие версии. В тексте merge естественен: вставки от двух пользователей просто оба оказываются в документе (CRDT обеспечивает это автоматически). Для структурированных данных merge сложнее.

Ключевой принцип хорошей merge policy - **семантическая корректность**: результат должен быть валидным состоянием системы, а не просто технически не конфликтующим. Если Алиса переименовала файл в 'report.pdf', а Боб переместил его в другую папку - корректный merge сохранит оба изменения.

**MongoDB** использует field-level merge при репликации: если два документа изменили разные поля - конфликта нет, оба изменения применяются. **CouchDB** реализует document-level версионирование с явными конфликтами: приложение само разрешает конфликт и записывает победившую версию. **Automerge** (CRDT) делает field-level merge автоматически для JSON-документов.

Алиса изменила поле `price: 100`, Боб изменил поле `description: 'new text'` в одном и том же JSON-объекте. Как должна работать корректная merge policy?

User Intent

Техническая корректность merge - необходимое, но не достаточное условие. Алиса удалила параграф потому что он устарел; Боб исправил опечатку в этом параграфе. CRDT merge сохранит параграф с исправленной опечаткой - технически верно, но **intent Алисы потерян**. Это называется intent conflict.

Intent-aware resolution - подход, при котором система пытается понять намерение пользователя, а не только технический diff. Это сложная задача: намерение не передаётся в протоколе явно. Решения: semantic types для операций, пользовательские аннотации, ML-классификация намерений.

**Notion** использует block-level granularity: если Алиса удалила блок целиком, а Боб редактировал текст внутри - победит удаление блока (structural-delete). Notion показывает notification 'Your changes were lost because the block was deleted'. Это намеренное UX-решение, а не баг.

Алиса удалила раздел документа (intent: structural-delete). Боб одновременно отформатировал заголовок этого раздела (intent: format). Как должна сработать intent-aware резолюция?

Resolution Impl

Практическая реализация conflict resolution - это pipeline из нескольких слоёв. Сначала детекция конфликта (concurrent операции на пересекающихся данных), затем классификация (LWW / merge / intent-based), затем резолюция и опциональная нотификация пользователя.

**Hybrid Logical Clock (HLC)** - замена wall clock для LWW: HLC = max(localTime, receivedTime) + counter. Монотонно растёт и учитывает causality. Используется в CockroachDB, YugabyteDB. При использовании HLC LWW-конфликты резолвятся детерминировано и корректно даже при clock skew до сотен миллисекунд.

Конфликты в collaborative системах - признак плохого дизайна, их нужно полностью исключить через pessimistic locking

Конфликты неизбежны при concurrent работе; задача - разработать правильную стратегию резолюции, а не запрещать параллельное редактирование

Pessimistic locking убивает collaborative UX: нельзя редактировать пока кто-то другой держит lock. Google Docs, Figma, Notion работают optimistically - принимают конфликты и резолвят их. Пользователи получают плавный опыт, а конфликты разрешаются прозрачно.

Два insert-операции в одну и ту же позицию документа - это конфликт, который требует LWW/intent-резолюции?

Итоги

  • LWW/FWW/Merge - три базовые стратегии; выбор зависит от семантики данных и допустимости потери
  • Field-level merge (MongoDB, Automerge) - лучше document-level: независимые изменения разных полей не конфликтуют
  • Intent-aware resolution добавляет семантику: structural-delete приоритетнее format; нотификация пользователю при потере изменений - обязательна

Связанные темы

Conflict resolution - центральная тема distributed систем с пересечениями в нескольких областях:

  • CRDT структуры — CRDT автоматически разрешает конфликты для вставок/удалений через математически доказанный merge; conflict resolution нужен для LWW-семантики поверх CRDT
  • Undo/Redo — Undo порождает особый класс конфликтов: инверсия операции конкурирует с последующими remote изменениями
  • Eventual Consistency — Conflict resolution - механизм достижения eventual consistency: все реплики в итоге приходят к одному состоянию

Вопросы для размышления

  • В spreadsheet Алиса установила формулу `=A1+B1` в ячейку C1, Боб одновременно записал туда значение `42`. Какая стратегия резолюции корректна и почему?
  • Как уведомлять пользователя о потере изменений - без того чтобы засыпать его алертами при активной collaborative работе?
  • Можно ли доверять wall clock timestamp для LWW в системе где клиенты - мобильные устройства с возможным clock drift?

Связанные уроки

  • dist-12-consistency
Конфликт-резолюция

0

1

Войти