Sync Engine: ключові поняття, типи та механізми роботи

Автор: IT Sectr Опубліковано: 2026-06-14 Час читання: 10 хв

Sync Engine — це компонент додатку, відповідальний за узгоджене оновлення даних між локальним сховищем пристрою та віддаленим сервером. У мобільних додатках Sync Engine забезпечує роботу в офлайні, фонову синхронізацію та вирішення конфліктів. За даними Google Firebase (2025), додатки з вбудованим Sync Engine показують на 25% вище утримання в регіонах з нестабільним з’єднанням.

Головне

  • Sync Engine — системний компонент, що координує обмін даними між локальним та віддаленим сховищами.
  • Incremental sync — передача лише змінених з моменту останньої синхронізації даних через чекпоїнти.
  • Push sync — сервер ініціює синхронізацію через FCM, WebSocket або long polling.
  • Snapshot-based sync — порівняння повного знімка даних з останньою версією для виявлення розбіжностей.
  • Conflict-free resolution — автоматичне або ручне вирішення колізій при одночасній зміні даних.

Що таке двигун синхронізації?

Sync Engine — це архітектурний шар між локальною базою даних та віддаленим API, який керує потоком даних в обох напрямках. Його завдання: відстежувати зміни, відправляти їх на сервер, отримувати зміни з сервера та вирішувати конфлікти. Користувач взаємодіє з локальними даними, а Sync Engine безшовно синхронізує їх з сервером.

Sync Engine буває вбудованим (Firebase Firestore, Couchbase Lite, Realm) та кастомним — написаним під конкретну бізнес-логіку. Вбудовані двигуни пропонують готовий функціонал offline-first та conflict resolution. Кастомні дають повний контроль над форматом даних, протоколом синхронізації та політикою конфліктів.

За даними Сравана Картік (2024), автора книги «Mobile Sync Engine Design Patterns», кастомний Sync Engine виправданий для додатків зі складною бізнес-логікою (фінанси, медицина, IoT), де кастомні правила злиття критичні. Для типових сценаріїв (нотатки, чати, стрічки) достатньо вбудованого Firestore або Realm.

kotlin
interface SyncEngine {
    suspend fun pull(lastSyncTimestamp: Long): SyncResult
    suspend fun push(operations: List<QueuedOperation>): PushResult
    suspend fun resolve(conflicts: List<Conflict>): ResolutionResult
    fun observeSyncState(): Flow<SyncState>
}

Цей інтерфейс описує мінімальний контракт Sync Engine: pull (завантаження змін з сервера), push (відправка локальних змін), resolve (обробка конфліктів) та observe (спостереження за станом синхронізації). Така абстракція дозволяє змінювати реалізацію без зміни шару Presentation.

Типи синхронізації: повна, інкрементальна та push

Full sync (повна синхронізація) — при кожному сеансі завантажується весь набір даних з сервера. Проста реалізація, але неприйнятна для великих обсягів: завантаження 10 000 записів при кожному відкритті додатку витрачає трафік та батарею. Full sync виправданий для довідкових даних (список країн) з рідкісними оновленнями.

Incremental sync (інкрементальна) — передаються лише записи, що змінилися з моменту останньої синхронізації. Сервер зберігає часову мітку останньої зміни для кожного запису або всього набору. Клієнт передає lastSyncTimestamp та отримує лише записи з updated_at > це значення. За даними Instagram Engineering (2024), incremental sync скорочує обсяг даних, що передаються, на 97% порівняно з full sync.

Push sync (сервер-ініційована) — сервер сам повідомляє клієнта про необхідність синхронізації через FCM (Firebase Cloud Messaging), WebSocket або SSE (Server-Sent Events). Клієнт не витрачає ресурси на періодичний поллінг. Push sync — оптимальний варіант для додатків реального часу: чати, сповіщення, лайки. Google Firebase Firestore використовує WebSocket для real-time sync з автоматичним fallback на HTTP polling.

ТипТрафікЗатримкаСкладністьЗастосування
Full syncВисокийВисокаНизькаДовідники, конфігурації
IncrementalНизькийНизькаСередняСтрічки, каталоги, профілі
Push syncМінімальнийМінімальнаВисокаЧати, сповіщення, колаборація

Гібридний підхід — комбінація типів: при старті додатку full sync для базових даних, потім incremental sync для оновлень, а для критичних подій — push sync через FCM. Це дає і швидкість, і економію ресурсів.

Incremental sync — як працюють чекпоїнти та дельти

Чекпоїнт — значення, яке клієнт зберігає між сесіями синхронізації. Зазвичай це updated_at останнього успішно синхронізованого запису. При наступній синхронізації клієнт передає чекпоїнт серверу, і той повертає всі записи з updated_at пізніше чекпоїнта. Cursor-based pagination — просунута версія, де сервер повертає курсор (покажчик на наступну сторінку) разом з даними.

Дельта-синхронізація — сервер обчислює diff між поточним станом даних та знімком, який бачив клієнт. Замість відправки всіх записів передаються лише операції (insert, update, delete). Це особливо ефективно для великих масивів даних, де змінилося лише кілька записів. Google Drive API (2025) використовує changes.list з pageToken для дельта-синхронізації файлів.

Стратегія «відкладених дельт» — на мобільному клієнті зміни не відправляються негайно, а буферизуються в Offline Queue. При досягненні порогу (10 операцій або 30 секунд) формується дельта-пакет та відправляється на сервер. За даними Dropbox Mobile Engineering (2024), батчинг дельт скоротив кількість HTTP-запитів на 65% та знизив споживання батареї на 12%.

kotlin
data class SyncCheckpoint(
    val lastUpdated: Long,
    val pageToken: String?,
    val version: Int
)

suspend fun syncIncremental(checkpoint: SyncCheckpoint): SyncResult =
    api.pullChanges(
        since = checkpoint.lastUpdated,
        token = checkpoint.pageToken
    )

SyncCheckpoint зберігає як часову мітку, так і курсор пагінації для довгих списків. Двопараметричний чекпоїнт гарантує, що жоден запис не буде пропущений або продубльований при синхронізації великих наборів даних.

Push sync — миттєва синхронізація через WebSocket та FCM

WebSocket — постійне двонаправлене з’єднання між клієнтом та сервером. Сервер відправляє оновлення відразу при зміні даних. WebSocket оптимальний для додатків реального часу: чати, стрімінг, колаборативна робота. Мінус: витрата батареї та трафіку на підтримання з’єднання (heartbeat). OkHttp WebSocket на Android та URLSessionWebSocketTask на iOS — вбудовані реалізації.

Firebase Cloud Messaging (FCM) — push-сповіщення, які сервер відправляє не для показу користувачу, а для тригера синхронізації. При отриманні silent push (data message) додаток прокидається та запускає Sync Engine. FCM не вимагає постійного з’єднання та економніший за WebSocket для рідкісних сповіщень.

SSE (Server-Sent Events) — односторонній канал, по якому сервер шле події клієнту. Простіший за WebSocket у реалізації, але не підтримує двосторонній зв’язок. EventSource API (JavaScript) та OkHttp SSE (Android) — популярні бібліотеки. SSE підходить для сповіщень про нові дані, коли клієнту не потрібно відправляти дані назад по тому ж каналу.

За даними WhatsApp Engineering (2024), їхній Sync Engine використовує комбінацію WebSocket для активної сесії та FCM для пробудження додатку в фоні: WebSocket відключається після 5 хвилин неактивності, і наступні оновлення доставляються через silent push.

Snapshot sync та версіонування даних

Snapshot-based sync — сервер періодично створює повний знімок даних (snapshot) та присвоює йому версію. Клієнт зберігає номер поточної версії. Якщо вона застаріла — завантажує новий знімок. Це проста та надійна стратегія, але неефективна для частих змін — щоразу завантажується повний набір даних.

Версіонування на рівні запису — кожен запис має поле version. При синхронізації клієнт відправляє версії всіх записів, а сервер повертає лише ті, чия версія змінилася. Це ефективніше за snapshot sync, але вимагає зберігання версій на клієнті. Vector Clocks — просунута техніка для розподілених систем, де кожен вузол присвоює свою версію та конфлікти вирішуються за partial order.

Snapshot з інкрементальним diff — гібридний підхід: рідкісний повний snapshot (раз на день) + incremental sync між ними. При старті після довгої відсутності клієнт завантажує snapshot, а при частих синхронізаціях — лише дельти. Git-подібний підхід — кожен коміт даних має хеш, і клієнт знає, від якого коміту відштовхуватися. Це реалізовано в Couchbase Lite Sync Gateway (2024) і є еталоном надійності.

kotlin
data class VersionedEntryT(
    val id: String,
    val data: T,
    val version: Long,
    val deleted: Boolean
)

fun SyncEngine.resolveVersion(local: VersionedEntry*, remote: VersionedEntry*): VersionedEntry* =
    when {
        local.version > remote.version -> local
        remote.version > local.version -> remote
        else -> resolveConflict(local, remote)
    }

Правило вирішення версій: якщо версії збігаються — змін немає. Якщо локальна версія новіша — перемагає локальна. Якщо серверна новіша — перемагає серверна. Тільки при рівних версіях, але різних даних — викликається conflict resolver. Last Write Wins з version-флагом — найпростіша, але надійна стратегія.

Як побудувати Sync Engine для мобільного додатку

Крок 1: Визначити модель даних — які сутності синхронізуються, як часто змінюються, який обсяг. Для кожної сутності зафіксувати стратегію (incremental / full / push) та допустимий час затримки синхронізації.

Крок 2: Вибрати протокол — REST з чекпоїнтами, GraphQL з Subscriptions або gRPC з bidirectional stream. GraphQL Subscriptions — популярний вибір для сучасних додатків: один протокол і на pull, і на push. Apollo Client (2025) підтримує offline sync через кеш на пристрої.

Крок 3: Реалізувати Offline Queue — локальне сховище змін з idempotency keys (див. статтю «Offline Queue»). Черга — фундамент надійного Sync Engine: без неї синхронізація не гарантує доставку змін.

Крок 4: Вибрати conflict resolver — LWW для простих випадків, CRDT для спільного редагування, Custom merge для бізнес-логіки. Правило: resolver повинен бути ідемпотентним — повторне застосування тієї ж операції повинно давати той же результат.

Крок 5: Моніторинг та метрики — логувати кожну синхронізацію: кількість записів, час виконання, кількість конфліктів, помилки. Firebase Crashlytics або Sentry (2025) дозволяють відстежувати помилки синхронізації в реальному часі.

За даними Realm Team (2024), типовий Sync Engine для мобільного додатку обробляє 100–500 синхронізацій в день на пристрій, передаючи в середньому 50–200 КБ даних за сесію. Оптимізація протоколу — стиснення Protobuf замість JSON — скорочує обсяг даних, що передаються, ще на 40–60%.

Часті запитання

Чим Sync Engine відрізняється від звичайного API-клієнта?

API-клієнт виконує разові запити та повертає результат. Sync Engine керує станом даних: відстежує зміни, буферизує їх в офлайні, синхронізує в фоні та вирішує конфлікти. Sync Engine — це API-клієнт + локальна БД + менеджер черг + conflict resolver.

Як часто потрібно запускати синхронізацію?

Оптимальна частота залежить від типу даних: критичні (повідомлення, замовлення) — через push sync в реальному часі; некритичні (стрічка, сповіщення) — incremental sync кожні 15–30 хвилин. WorkManager PeriodicWorkRequest дозволяє налаштувати інтервал на Android з урахуванням Doze Mode.

Що робити при конфлікті синхронізації?

Автоматична стратегія — Last Write Wins (по timestamp сервера). Якщо це неприпустимо — CRDT або кастомний merge на сервері. В крайньому випадку — зберегти обидві версії та запропонувати користувачу вибір. Головне правило: ніколи не втрачати дані користувача при вирішенні конфлікту.

Який Sync Engine вибрати: кастомний чи готовий (Firebase)?

Firebase Firestore — найкращий вибір для типових додатків (чати, стрічки, соцмережі). Він надає offline-first, real-time sync та conflict resolution «з коробки». Кастомний Sync Engine виправданий при специфічній бізнес-логіці, вимогах до приватності даних або інтеграції з legacy-сервером.

Як тестувати Sync Engine?

Авто-тести — mock сервера з передбачуваними відповідями, тестування Offline Queue та conflict resolver. Інтеграційні тести — реальний сервер в тестовому середовищі, симуляція мережевих затримок з Network Link Conditioner. E2E-тести — два пристрої, що синхронізуються через один акаунт, перевірка консистентності даних після серії операцій.

Підсумки

  • Sync Engine — компонент, що керує двонаправленою синхронізацією даних між пристроєм та сервером.
  • Full sync — завантаження всіх даних; простий, але неефективний для великих обсягів.
  • Incremental sync — передача лише змін з моменту останнього чекпоїнта; оптимальний для типових сценаріїв.
  • Push sync — сервер ініціює синхронізацію через FCM або WebSocket; мінімальна затримка.
  • Snapshot з інкрементальним diff — гібрид, що поєднує рідкісний повний знімок з частими дельтами.
  • Conflict resolver — обов’язковий компонент; LWW, CRDT або кастомний merge з пріоритетом збереження даних користувача.
  • Готові рішення (Firebase, Couchbase, Realm) підходять для 80% додатків; кастомний Sync Engine — для складної бізнес-логіки.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також