Sync Engine — デバイスのローカルストレッジとリモートサーバーの間でデータを一貫して更新するアプリケーションコンポーネントです。モバイルアプリでは、Sync Engineがオフライン動作、バックグラウンド同期、コンフリクト解決を提供します。Google Firebase (2025)によると、Sync Engine組み込みのアプリは不安定な接続の地域でリテンションが25%高くなります。
まとめ
Sync Engine — ローカルデータベースとリモートAPIの間のアーキテクチャ層で、両方向のデータ流を管理します。仕事は、変更の追跡、サーバーへの送信、サーバーからの変更受信、コンフリクトの解決です。ユーザーはローカルデータと矛盾し、Sync Engineがそれをサーバーとシームレスに同期します。
Sync Engineは組み込み(Firebase Firestore、Couchbase Lite、Realm)またはカスタム— 特定のビジネスロジックに対して書かれたものです。組み込みエンジンは、即座に使えるoffline-first機能とコンフリクト解決を提供します。カスタムエンジンは、データ形式、同期プロトコル、コンフリクトポリシーを完全に制御できます。
Sravana Karthik (2024)『Mobile Sync Engine Design Patterns』の著者によると、カスタムSync Engineは複雑なビジネスロジック(金融、医療、IoT)を扱うアプリに適しており、カスタムマージルールが重要です。一般的なシナリオ(ノート、チャット、フィード)では、組み込みのFirestoreまたはRealmで十分です。
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(同期状態の監視)。この抽象化により、プレゼンテーション层を変えずに実装を変更できます。
フル同期 (Full sync) — 同期ごとにサーバーから全データセットを読み込みます。実装は簡単ですが、大量のデータには不適し:アプリを開くたびに10,000件をダウンロードすると、トラフィックやバッテリーを消費します。フル同期は、更新の少ないリファレンスデータ(国名リスト)に適しています。
インクリメンタル同期 — 前回の同期から変更されたレコードのみが転送されます。サーバーは各レコードまたは全セットの最終変更時刻を保存します。クライアントがlastSyncTimestampを送信し、updated_at > その値のレコードのみを受け取ります。Instagram Engineering (2024)によると、インクリメンタル同期はフル同期に比べてデータ転送量を97%減少させます。
プッシュ同期(サーバー始動) — サーバーがFCM (Firebase Cloud Messaging)、WebSocket、SSE (Server-Sent Events)を介してクライアントに同期の必要を通知します。クライアントは定期的なポーリングにリソースを消費しません。プッシュ同期はリアルタイムアプリ(チャット、通知、いいね)に最適です。Google Firebase Firestoreは、HTTP pollingへの自動フォールバックを備えたWebSocketによるリアルタイム同期を提供しています。
| タイプ | トラフィック | 遅延 | 複雑さ | 用途 |
|---|---|---|---|---|
| フル | 高い | 高い | 低い | ディレクトリ、設定 |
| インクリメンタル | 低い | 低い | 中程度 | フィード、カタログ、プロフィール |
| プッシュ | 最小 | 最小 | 高い | チャット、通知、コラボレーション |
ハイブリッドアプローチ — タイプの組み合わせ:アプリ起動時にベースラインデータのフル同期、その後更新のインクリメンタル同期、クリティカルなイベントにはFCMを介してプッシュ同期。これにより、速度とリソース節約の両方を得られます。
チェックポイント (Checkpoint) — クライアントが同期セッション間に保存する値です。通常は、最後に成功同期されたレコードのupdated_atです。次回の同期で、クライアントはチェックポイントをサーバーに送信し、サーバーはチェックポイントより後のupdated_atを持つすべてのレコードを返します。カーソルベースのページネーション — サーバーがデータとともにカーソル(次のページへのポインター)を返すより進んだ仕組みです。
デルタ同期 — サーバーがデータの現在の状態と、クライアントが前回見たスナップショットの差分を計算します。すべてのレコードを送信する代わりに、操作(insert、update、delete)のみが転送されます。これは、いくつかのレコードのみが変更された大きなデータセットに特に効果的です。Google Drive API (2025)は、ファイルのデルタ同期にpageToken付きのchanges.listを使用しています。
「待機デルタ」戦略 — モバイルクライアントでは、変更は即時に送信されず、Offline Queueにバッファされます。スレッショルド(10回の操作または30秒)に達すると、デルタパッケージが作成されサーバーに送信されます。Dropbox Mobile Engineering (2024)によると、デルタのまとめ処理によりHTTPリクエスト数が65%減少し、バッテリー消費が12%減少しました。
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は、長いリストのために時刻とページネーションカーソルの両方を保存します。二つのパラメータを持つチェックポイントにより、大きなデータセットを同期する際にレコードが見逃されたり複製されたりすることがありません。
WebSocket — クライアントとサーバーの間の持続的な双向通信接続です。データが変更されると、サーバーが即時に更新を送信します。WebSocketはリアルタイムアプリ(チャット、ストリーミング、コラボレーション)に最適です。欠点は、接続を維持するためのバッテリーとトラフィック消費(heartbeat)です。AndroidではOkHttp WebSocket、iOSではURLSessionWebSocketTaskが組み込みの実装です。
Firebase Cloud Messaging (FCM) — サーバーがユーザー表示のためではなく、同期をトリガーするために送信するプッシュ通知です。サイレントプッシュ(データメッセージ)を受信すると、アプリが起動し、Sync Engineが始動します。FCMは持続的な接続を必要とせず、れたな通知にはWebSocketよりも節約できます。
SSE (Server-Sent Events) — サーバーがクライアントにイベントを送信する単方向チャネルです。WebSocketより実装が簡単ですが、双向通信はサポートしません。EventSource API (JavaScript)とOkHttp SSE (Android)が人気のライブラリです。SSEは、クライアントが同じチャネルを通じてデータを送り返す必要がない場合の新しいデータについての通知に適しています。
WhatsApp Engineering (2024)によると、弼のSync Engineは、アクティブセッションにはWebSocketを、バックグラウンドでアプリを起動するにはFCMを組み合わせています:WebSocketは30分間の非活動で切断され、その後の更新はサイレントプッシュで配信されます。
スナップショットベースの同期 — サーバーが定期的にデータの完全なスナップショットを作成し、バージョンを付与します。クライアントは現在のバージョン番号を保存します。それが古い場合は、新しいスナップショットをダウンロードします。これは簡単で信頼性の高い戦略ですが、頻繁な変更には効率的ではありません—同期ごとに全データセットがダウンロードされます。
レコード別バージョニング — 各レコードにはversionフィールドがあります。同期中に、クライアントがすべてのレコードのバージョンを送信し、サーバーはバージョンが変わったもののみを返します。これはスナップショット同期より効率的ですが、クライアントでバージョンを保存する必要があります。ベクトルクロック (Vector Clocks) — 分散システムのための高度な技術で、各ノードが独自のバージョンを付与し、衝突は部分順序で解決されます。
インクリメンタル差分付きスナップショット — ハイブリッドアプローチ:れたな完全スナップショット(1日1回)+ その間のインクリメンタル同期。長期不在後の起動時にはスナップショットをロードし、頻繁な同期時にはデルタのみを転送します。Gitライクのアプローチ — 各データコミットにハッシュがあり、クライアントはどのコミットから始めるかを知っています。これはCouchbase Lite Sync Gateway (2024)で実装され、信頼性の金標盤となっています。
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)
}
バージョン解決ルール:バージョンが一致する場合—変更はありません。ローカルバージョンが新しい場合—ローカルが勝ちます。サーバーバージョンが新しい場合—サーバーが勝ちます。バージョンが等しくデータが異なる場合のみ、コンフリクトレゾルバーが呼ばれます。バージョンフラグ付きLast Write Wins — 最も簡単で信頼性のある戦略です。
ステップ1:データモデルの定義 — どのエンティティが同期されるか、変更の頻度、ボリュームを確認します。各エンティティに対して戦略(インクリメンタル / フル / プッシュ)と許容できる同期遅延を決めます。
ステップ2:プロトコルの選択 — チェックポイント付きREST、Subscriptions付きGraphQL、または双向ストリーム付きgRPC。GraphQL Subscriptions — 現代的なアプリに人気の選択肢:pullとpushの両方に1つのプロトコルです。Apollo Client (2025)はデバイスキャッシュを介してオフライン同期をサポートしています。
ステップ3:Offline Queueの実装 — アイデンポテンシーキー付きのローカル変更保存(記事『Offline Queue』参照)。キューは信頼性のあるSync Engineの基盤です:これがなければ、同期は変更の配信を保証できません。
ステップ4:コンフリクトレゾルバーの選択 — 簡単な場合はLWW、共同編集にはCRDT、ビジネスロジックにはカスタマージ。ルール:レゾルバーはアイデンポテントである必要があります—同じ操作を再度適用すると、同じ結果が得られるはずです。
ステップ5:モニタリングとメトリクス — 同期ごとに以下をログに記録:レコード数、実行時間、コンフリクト数、エラー。Firebase CrashlyticsまたはSentry (2025)により、リアルタイムで同期エラーを追跡できます。
Realm Team (2024)によると、一般的なモバイルアプリのSync Engineは、デバイスあたり毎日100–500回の同期を処理し、セッションあたり平均50–200KBのデータを転送します。プロトコルの最適化 — JSONの代わりにProtobuf圧縮を使用すると、データ転送量がさらに40–60%減少します。
よくある質問
APIクライアントはワンショットのリクエストを実行し、結果を返します。Sync Engineはデータの状態を管理します:変更を追跡し、オフラインでバッファし、バックグラウンドで同期し、コンフリクトを解決します。Sync Engine = APIクライアント + ローカルDB + キューマネージャー + コンフリクトレゾルバー。
最適な頻度はデータの種類によります:クリティカル(メッセージ、注文)— リアルタイムのプッシュ同期;非クリティカル(フィード、通知)— 15–30分ごとのインクリメンタル同期。WorkManager PeriodicWorkRequestにより、Doze Modeを考慮してAndroid上で同期間隔を設定できます。
自動戦略 — Last Write Wins(サーバーのタイムスタンプによる)。これが不可能な場合—CRDTまたはサーバー上でのカスタマージ。最終手段として—両方のバージョンを保存し、ユーザーが選択できるようにします。最重要なルール:コンフリクト解決時にユーザーのデータを絶対に失ってはいけません。
Firebase Firestore — 一般的なアプリ(チャット、フィード、ソーシャルネットワーク)に最適です。offline-first、リアルタイム同期、コンフリクト解決をボックスから提供します。カスタムSync Engineは、特定のビジネスロジック、データプライバシー要件、レガシーサーバーとの統合に適しています。
単体テスト — 予測可能な応答を返すモックサーバーで、Offline Queueとコンフリクトレゾルバーをテスト。統合テスト — テスト環境の実サーバーで、Network Link Conditionerを使ってネットワーク遅延をシミュレート。E2Eテスト — 二つのデバイスが一つのアカウントを通じて同期し、一連の操作後にデータの一貫性を確認します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。