Протокол синхронизации Dexie Cloud

Протокол синхронизации в Dexie Cloud строится вокруг идеи двунаправленного обмена изменениями между локальной базой данных и удалённым хранилищем, при этом локальная база в Dexie.js рассматривается как первичный источник операций. Вместо классической модели «перезаписать состояние» используется модель журналируемых изменений (operation log / change feed), где каждое изменение представляется как событие с метаданными, позволяющими восстановить порядок, идентичность и контекст выполнения.

Основой протокола является разделение на три слоя: локальный журнал операций, транспортный слой синхронизации и удалённый журнал/состояние. Такое разделение позволяет минимизировать зависимость от сетевого соединения и обеспечить детерминированное разрешение конфликтов.

Локальный журнал изменений

Каждая модификация данных в Dexie.js фиксируется в локальном журнале изменений. Этот журнал является источником истины до момента синхронизации и включает:

  • тип операции (create, update, delete)
  • ключ объекта
  • изменённые поля или полный снимок (в зависимости от стратегии)
  • временную метку локального устройства
  • уникальный идентификатор операции
  • версию схемы/ревизии

Важный аспект — неизменяемость записей журнала. Каждая операция не редактируется, а добавляется как новая запись. Это позволяет выполнять повторную отправку и восстановление состояния без потери семантики.

Локальный журнал также используется как механизм отката: при конфликте сервер может прислать альтернативную версию цепочки изменений, и клиент способен пересобрать состояние, переиграв операции.

Модель идентичности и ревизий

Синхронизационный протокол опирается на концепцию ревизий (revision IDs). Каждая сущность в базе получает стабильный идентификатор и набор версий. Ревизия формируется на основе:

  • предшествующего состояния
  • применённой операции
  • серверного подтверждения

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

Ключевым элементом является детерминированность генерации ревизий: одинаковый набор операций в одинаковом порядке приводит к одинаковому результату на разных устройствах.

Этапы синхронизации

Синхронизация в Dexie Cloud состоит из двух основных потоков: push (от клиента к серверу) и pull (от сервера к клиенту).

Push-поток

На этапе отправки клиент агрегирует локальные изменения из журнала и формирует пакет (mutation batch). Этот пакет включает:

  • список операций
  • базовую ревизию (точку отсчёта)
  • идентификатор клиента
  • временные метки

Сервер проверяет применимость операций относительно текущего состояния. Если данные на сервере не изменились с момента базовой ревизии, изменения применяются напрямую. Если изменения уже произошли, запускается механизм конфликтного разрешения.

Pull-поток

При получении изменений клиент запрашивает у сервера дельту изменений, начиная с последней известной ревизии. Сервер возвращает:

  • список новых операций
  • удалённые или модифицированные сущности
  • обновлённые ревизии

Клиент применяет полученные изменения поверх локального состояния, обеспечивая согласованность данных.

Дифференциальная синхронизация

Протокол не передаёт полные состояния объектов при каждом изменении. Вместо этого используется дифференциальный подход: передаются только изменения полей. Это снижает объём трафика и ускоряет синхронизацию.

Существует два режима:

  • field-level diff: передаются только изменённые поля
  • object snapshot: передаётся полный объект (используется при сложных конфликтах или восстановлении)

Выбор режима зависит от политики коллекции и структуры данных.

Очередь операций и гарантии доставки

Локальная очередь операций в Dexie.js работает по принципу at-least-once delivery. Это означает, что каждая операция гарантированно будет доставлена минимум один раз, но может быть повторно отправлена при сбоях сети.

Для предотвращения дублирования на серверной стороне используются:

  • уникальные operation ID
  • идемпотентное применение операций
  • дедупликация по ключам событий

Таким образом достигается баланс между надёжностью и простотой протокола.

Конфликты и стратегии разрешения

Конфликты возникают при одновременном изменении одной сущности на разных устройствах. Протокол предусматривает несколько стратегий:

Last write wins (LWW)

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

Server-authoritative merge

Сервер выполняет слияние изменений на уровне полей. Если два изменения затрагивают разные поля, они объединяются. При конфликте одного поля применяется серверная политика приоритета.

Custom resolver

В сложных приложениях допускается подключение пользовательской функции разрешения конфликтов. Она получает:

  • локальную версию
  • серверную версию
  • историю операций

и возвращает итоговое состояние.

Транзакционная модель синхронизации

Каждая синхронизационная операция рассматривается как транзакция, включающая несколько этапов:

  1. фиксация локальных изменений
  2. отправка пакета на сервер
  3. подтверждение применения
  4. обновление локальной ревизии
  5. удаление подтверждённых операций из очереди

Если любой этап не завершается успешно, транзакция остаётся в незавершённом состоянии и повторяется при следующей синхронизации.

Это обеспечивает устойчивость к обрывам соединения и перезапускам приложения.

Версионирование схемы данных

Синхронизационный протокол учитывает эволюцию структуры данных. Каждая операция содержит версию схемы, что позволяет:

  • корректно интерпретировать поля при изменениях модели
  • поддерживать обратную совместимость
  • выполнять миграции на клиенте и сервере независимо

При несовпадении версий применяется слой адаптации, который преобразует данные в актуальный формат.

Инкрементальные обновления и cursor-based синхронизация

Для масштабируемости используется курсорная модель синхронизации. Вместо запроса «всех изменений» клиент хранит cursor — позицию в глобальном журнале сервера.

Сервер возвращает изменения, начиная с этого cursor, что позволяет:

  • избегать повторной передачи данных
  • ускорять синхронизацию при больших объёмах
  • упрощать восстановление после длительного оффлайна

Работа в оффлайн-режиме

Локальная база Dexie.js функционирует автономно, даже при отсутствии соединения. Все операции продолжают записываться в журнал, а синхронизация откладывается до восстановления связи.

При длительном оффлайне возможно накопление большого количества операций, поэтому протокол поддерживает:

  • сжатие операций (operation compaction)
  • объединение последовательных изменений
  • удаление устаревших промежуточных состояний

Механизм подтверждений

Каждая операция после успешного применения на сервере получает acknowledgement (ACK), который включает:

  • server revision ID
  • timestamp сервера
  • статус применения

Клиент использует ACK для очистки локального журнала и фиксации синхронизированного состояния.

Если ACK не получен, операция остаётся в очереди и будет повторно отправлена.

Согласованность и eventual consistency

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

Достижение согласованности обеспечивается:

  • детерминированным порядком применения операций
  • идемпотентностью
  • курсорной синхронизацией
  • ревизионным графом

Оптимизация сетевого взаимодействия

Для уменьшения нагрузки протокол использует:

  • батчинг операций
  • сжатие payload (gzip/brotli на уровне транспорта)
  • приоритизацию критических изменений
  • отложенную синхронизацию фоновых данных

Также применяется адаптивная частота синхронизации в зависимости от активности пользователя.

Безопасность синхронизационного канала

Хотя протокол ориентирован на данные, он включает механизмы защиты:

  • аутентификация клиента перед обменом данными
  • проверка прав доступа на уровне коллекций
  • валидация операций на сервере
  • предотвращение replay-атак через уникальные идентификаторы операций

Каждая операция проверяется не только по структуре, но и по разрешениям текущего пользователя.

Итоговая модель поведения данных

В совокупности протокол синхронизации формирует модель, где:

  • локальные операции имеют приоритет до момента синхронизации
  • сервер обеспечивает глобальную согласованность
  • изменения распространяются инкрементально
  • конфликты разрешаются предсказуемыми стратегиями
  • оффлайн-режим не нарушает целостность данных

Такая архитектура позволяет строить распределённые приложения на базе Dexie Cloud без необходимости вручную управлять синхронизацией состояния и сетевой логикой.