web-dev-qa-db-ja.com

データベース表現のアプリクラウド同期のベストプラクティス

私は、クックブックのようなAndroidアプリを計画しています。これにより、ユーザーは電子ジュースのレシピを保存/追加/編集したり、材料を追跡したりできます。内部的には、ユーザーのデバイス上のデータベース(SQLiteラッパーであるRoom)のデータと、ユーザーのGoogleドライブにコピーを保持して、他のデバイスからアクセスできるようにします。Googleドライブ側では、データベースはJSONで表されます。

私が行き詰まっているのは、どのようにして同期を最も効率的にし、データ破損の可能性を最小限にするのですか?変更のたびにデータベース全体を書き直したくないのは確かです。これは非常に高額で、データをめちゃくちゃにする可能性が最も高いでしょう。

私が検討している他のアプローチは次のとおりです。

  1. エントリのJSONArrayを含むすべてのテーブル(最新の変更のタイムスタンプを含む)ごとに個別のJSONファイルを保持します。肯定的な面では、すべての準静的データを書き直す必要はありません。マイナス面として、最も脆弱なすべてのデータ(現在のレシピ、在庫にある材料など)は、同様に脆弱なままです。

  2. サブフォルダと影響を受けるファイル/エントリの両方で最新の変更のタイムスタンプを含む個別のファイルにすべてのエントリを持つすべてのテーブルのサブフォルダを保持します。これはデータ破損の可能性を最小限に抑える必要がありますが、多すぎるファイルを処理することは良い考えのようには思えません-一つには、それは高すぎるでしょう。

正直なところ、これまでクライアントサーバーアプリを処理するだけでよかった人として、私は少し奥が深いので、アドバイスをいただければ幸いです。

2
Kaworu

最終的に整合性のある分散システムを作成しようとしています。それらは本質的に複雑です。解決策がないので理解できます解決策がない

たとえば、「電話」と「タブレット」という2つのデバイスを持つユーザーと、次の一連のイベントを考えてみます。

  • スマートフォンとタブレットは同じデータベースで起動し、ネットワークから切断されます。
  • 午後1時に、ユーザーはタブレットの「レモンバー」レシピを削除します。
  • 午後2時に、ユーザーは自分の電話で「レモンバー」のレシピを編集します。
  • 午後3時に、電話はクラウドバックアップと同期します。バックアップされたデータベースには、レモンバーの編集が含まれます。
  • 午後4時、タブレットはクラウドバックアップと同期します。しかし今、バックアップされたデータベースには、タブレットが削除したいレコードの編集が含まれています。何をすべきか?

バージョン管理システムでは、これは「マージの競合」となり、手動で解決する必要があります。ただし、少なくともコンシューマーアプリでは、競合を解決するためのユーザーインターフェイスを実装することは一般に望ましくありません。

考えられる1つのアプローチは、クエリ可能なデータベースの状態の概念と、その状態に至る一連のイベントを分離することです( Event Sourcing )。状態は、すべてのイベントの再生から再計算できます。ここでは、複数のイベントストリームをどのようにマージするか、特にイベントをどのように順序付けるかという難しい問題が残っています。多くの場合、イベントのタイムスタンプで並べ替え、競合が発生した場合は「最後に勝った」戦略でマージします。ただし、正確なマージルールは問題のドメインによって異なります。常に機能する普遍的なアプローチはありません。

特に、この結果、すべてのデバイスは最終的に同じ状態を示しますが(デバイスは一貫性があります)、マージがデータ損失またはデータ品質損失につながる可能性が高くなります。消費者向けアプリの場合、特に競合が発生する可能性が少ないため、これはおそらくある程度許容できます。ただし、これは正確な要件によって異なります。

このようなイベント指向のアプローチでは、イベントログをクラウドバックアップに保存し、場合によってはデータベーススナップショットを保存します。ただし、別のデバイスが正しく同期するのを妨げずに古いスナップショットを削除することは非常に難しいため、スナップショットを完全に回避するのが最善です。各ログに一意の名前を付けることができます。デバイス+タイムスタンプまたはコンテンツのハッシュに基づきます。ファイルが不変の場合、これにより同期が簡素化されます。所有しているファイルはアップロードできますが、クラウドはそうではありません。クラウドにある新しいログをダウンロードします(のコンテンツのアドレス可能なストレージのアイデアも比較してください) )。同期には、ローカルデータベースの状態がイベントログから再構築されることが含まれますが、かなり小さいデータベースの場合は問題になりません。

アプリケーションの状態の真のソースとして機能する独自のサーバーを実行すると、これらすべてがはるかに簡単になります。通常、イベントはすぐにサーバーに送信され、そこで新しい状態が生成されます。デバイスが切断されている場合、競合が発生した場合にこれらのイベントが破棄される可能性があることを理解した上で、後でイベントをバッファーするオフラインモードを提供できます。

イベントの定義に関する注意:イベントでは、エンティティを新しいバージョンに置き換えることはできませんが、論理的に一貫性のあるデータモデルをもたらす小さな自己完結型の変更を記述します。これにより、イベントをマージしやすくなります。たとえば、レシピを編集されたバージョンに置き換えるイベントは問題があります。 「お気に入りとしてマーク」、「材料の量を変更」、「ステップを挿入」、「ステップを編集」という複数のイベントを作成する方がよい場合があります。エンティティは、イベントの順序に依存するIDで参照してはならないことに注意してください。自動インクリメントID。代わりに、UUIDを優先してください。

4
amon