web-dev-qa-db-ja.com

クライアントサーバーデータベースの同期

中央サーバー上のデータを常にオンラインではないクライアントアプリケーションと同期させるための一般的な戦略を探しています。

私の特定のケースでは、Android sqliteデータベースを使用した電話アプリケーションと、PHP MySQLデータベースを使用したWebアプリケーションがあります。

ユーザーは、電話アプリケーションとWebアプリケーションで情報を追加および編集できます。電話がサーバーとすぐに通信できない場合でも、1つの場所で行われた変更がどこにでも反映されるようにする必要があります。

電話からサーバーへ、またはその逆にデータを転送する方法は関係ありません。たとえば、MySQLで利用可能なレプリケーション機能を使用できないため、特定の技術についてのみ言及しています。

クライアントとサーバー間のデータ同期の問題は長い間存在しており、問題を処理するためのパターンに関する情報(記事、書籍、アドバイスなど)が欲しいことを知っています。長所、短所、トレードオフを比較するために同期を処理するための一般的な戦略について知りたいです。

78
Scott Saunders

最初に決定する必要があるのは、変更が競合する場合にどちらの側が「権限がある」と見なされるかについての一般的なポリシーです。

つまり、1月5日の午後10時にサーバーでレコード#125が変更され、1月5日の午後11時に電話の1つで同じレコードが変更されたとします(クライアントAと呼びましょう)。最終同期は1月3日でした。その後、ユーザーは、たとえば1月8日に再接続します。

変更が必要なものを識別することは、クライアントとサーバーの両方が最後の同期の日付を知っているという意味で「簡単」であるため、何でも作成または更新されます(最後の同期を調整する必要があるため、これについては以下を参照)。

したがって、変更された唯一のレコードが#125であるとします。 2つのうちの一方が自動的に「勝ち」、他方を上書きすることを決定するか、ユーザーがどちらのバージョン(サーバーまたはクライアント)が正しいかを判断して他方を上書きする調整フェーズをサポートする必要があります。

この決定は非常に重要であり、クライアントの「役割」を重視する必要があります。特に、クライアントとサーバーの間だけでなく、異なるクライアントが同じレコードを変更できる場合に潜在的な競合がある場合。

[#125を2番目のクライアント(クライアントB)が変更できると仮定すると、まだ同期していないクライアントBが同じレコードの別のバージョンを提供する可能性があり、以前の競合解決は無効になります]

上記の「作成または更新」ポイントについて...レコードがクライアントの1つから発信されている場合、どのように適切に識別することができますか?あなたの問題の領域で理にかなっています)?アプリがビジネスの連絡先のリストを管理しているとします。クライアントAが新しく作成したJohn Smithを追加する必要があり、サーバーにクライアントDが昨日作成したJohn Smithがある場合...異なる人物ではないことを確認できないため、2つのレコードを作成しますか?この競合も調整するようユーザーに依頼しますか?

クライアントはデータのサブセットの「所有権」を持っていますか?つまりクライアントBがエリア#5のデータの「権限」として設定されている場合、クライアントAはエリア#5のレコードを変更/作成できますか? (これにより、一部の競合解決が容易になりますが、状況によっては実行不可能であることが判明する場合があります)。

要約すると、主な問題は次のとおりです。

  • 新しいレコードを作成する前に、切り離されたクライアントがサーバーにアクセスしていない可能性があることを考慮して、「アイデンティティ」を定義する方法。
  • 前の状況では、ソリューションがどれだけ高度になっても、データの重複が発生する可能性があるため、これらを定期的に解決する方法と、「レコード#675」と見なされるものが実際にマージ/置き換えられたことをクライアントに通知する方法を予測する必要がありますレコード#543
  • 競合をfiatで解決するかどうかを決定します(たとえば、「前者が最後の同期以降に更新された場合、サーバーバージョンは常にクライアントのバージョンよりも優先されます」)または手動介入
  • fiatの場合、特にクライアントが優先されると決定した場合は、まだ同期されていない他の処理方法にも注意する必要があります。いくつかの変更が追加される可能性のあるクライアント。
  • 前の項目は、データの粒度を考慮していません(説明を簡単にするため)。私の例のように、「記録」レベルで推論する代わりに、フィールドレベルで変更を記録する方がより適切であると言うことができます。または、一連のレコード(たとえば、個人レコード+住所レコード+連絡先レコード)をまとめて、それらの集計を一種の「メタレコード」として扱います。

書誌:

  • これについては、もちろん Wikipedia をご覧ください。

  • 単純な同期アルゴリズムVdirsyncer の作者による

  • データ同期に関するOBJCの記事

  • SyncML®:モバイルデータの同期と管理 (O'Reilly Safariの本)

  • 競合のない複製されたデータ型

  • Optimistic Replication 斉藤TO(HP Laboratories)およびMARC SHAPIRO(Microsoft Research Ltd.)-ACM Computing Surveys、Vol。 V、No。N、3 2005

  • アレクサンダー・トラウド、ユルゲン・ナグラー・アイライン、フランク・カーグル、マイケル・ウェーバー。 2008. SyncMLの再利用による周期的なデータ同期。モバイルデータ管理に関する第9回国際会議(MDM '08)の議事録。 IEEE Computer Society、ワシントンDC、米国、165-172。 DOI = 10.1109/MDM.2008.10 http://dx.doi.org/10.1109/MDM.2008.1

  • Lam、F.、Lam、N.、およびWong、R.2002。モバイルXMLデータの効率的な同期。情報と知識の管理に関する第11回国際会議の議事録(McLean、米国、バージニア州、2002年11月4日-09日)。 CIKM '02。 ACM、ニューヨーク、NY、153-160。 DOI = http://doi.acm.org/10.1145/584792.58482

  • Cunha、P. R. and Maibaum、T. S. 1981.リソース&equil;抽象データ型+同期-メッセージ指向プログラミングの方法論-。第5回ソフトウェアエンジニアリングに関する国際会議の議事録(米国カリフォルニア州サンディエゴ、1981年3月9日から12日)。ソフトウェア工学に関する国際会議。 IEEE Press、Piscataway、NJ、263-272。

(最後の3つはACMデジタルライブラリからのものであり、メンバーであるか、他のチャネルから入手できるかはわかりません)。

Dr.Dobbs サイトから:

  • SQL Server CEとSQL RDAを使用したアプリの作成by Bill Wagner 2004年5月19日(デスクトップとモバイルPCの両方のアプリケーションを設計するためのベストプラクティス-Windows/.NET)

Arxiv.orgから:

  • A Conflict-Free Replicated JSON Datatype -この論文は、JSON CRDT実装について説明しています(Conflict-free replicated datatypes-CRDTs-は、同時変更をサポートし、そのような同時更新の収束を保証するデータ構造のファミリーです) 。
85
p.marino

すべてのテーブルにtimestamp列を用意し、挿入または更新するたびに、影響を受ける各行のタイムスタンプ値を更新することをお勧めします。次に、タイムスタンプが宛先データベースにあるタイムスタンプよりも新しいかどうかをチェックして、すべてのテーブルを反復処理します。新しい場合は、挿入または更新する必要があるかどうかを確認します。

観測1:行はソースdbから削除され、サーバーdbでも同じようにする必要があるため、物理的な削除に注意してください。これを解決して、物理的な削除を回避したり、タイムスタンプ付きのすべての削除をテーブルに記録したりできます。次のようなものです:DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp)したがって、DeletedRowsテーブルのすべての新しい行を読み取り、table_name、pk_column、pk_column_valueを使用してサーバーで削除を実行する必要があります。

所見2:別のテーブルに関連するテーブルにデータを挿入すると失敗する可能性があるため、FKに注意してください。データを同期する前に、すべてのFKを非アクティブ化する必要があります。

誰かが同様の設計上の問題に対処していて、複数のAndroidデバイス間で変更を同期する必要がある場合は、 Google Cloud Messaging for Android (GCM)を確認することをお勧めします。

1つのクライアントで行った変更を他のクライアントに伝達する必要がある1つのソリューションに取り組んでいます。そして、概念実証の実装(サーバーとクライアント)を実装したところ、それは魅力のように機能します。

基本的に、各クライアントは差分の変更をサーバーに送信します。例えば。リソースID ABCD1234の値が100から99に変更されました。

サーバーはデータベースに対してこれらのデルタの変更を検証し、変更を承認(クライアントが同期)してデータベースを更新するか、変更を拒否(クライアントが同期しない)します。

サーバーによって変更が承認されると、サーバーはGCMを介して他のクライアント(デルタ変更を送信したクライアントを除く)に通知し、同じデルタ変更を含むマルチキャストメッセージを送信します。クライアントはこのメッセージを処理し、データベースを更新します。

クールなことは、これらの変更がほぼ瞬時に伝播されることです!!!それらのデバイスがオンラインの場合。また、これらのクライアントにポーリングメカニズムを実装する必要はありません。

デバイスのオフライン時間が長すぎて、配信のためにGCMキューで100を超えるメッセージが待機している場合、GCMはそれらのメッセージを破棄し、デバイスがオンラインに戻ったときに特別なメッセージを送信することに注意してください。その場合、クライアントはサーバーと完全に同期する必要があります。

このチュートリアル もチェックして、CGMクライアントの実装を開始します。

5
jogo

これは、Xamarinフレームワークを使用している開発者に回答します( https://stackoverflow.com/questions/40156342/sync-online-offline-data を参照)

Xamarinフレームワークを使用してこれを実現する非常に簡単な方法は、Azureのオフラインデータ同期を使用することです。オンデマンドでサーバーからデータをプッシュおよびプルできます。読み取り操作はローカルで実行され、書き込み操作はオンデマンドでプッシュされます。ネットワーク接続が切断された場合、書き込み操作は接続が復元されるまでキューに入れられ、実行されます。

実装はかなり単純です。

1)Azureポータルでモバイルアプリを作成します(ここで無料で試すことができます https://tryappservice.Azure.com/

2)クライアントをモバイルアプリに接続します。 https://Azure.Microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started/

3)ローカルリポジトリをセットアップするコード:

const string path = "localrepository.db";

//Create our Azure mobile app client
this.MobileService = new MobileServiceClient("the api address as setup on Mobile app services in Azure");

//setup our local sqlite store and initialize a table
var repository = new MobileServiceSQLiteStore(path);

// initialize a Foo table
store.DefineTable<Foo>();

// init repository synchronisation
await this.MobileService.SyncContext.InitializeAsync(repository);
var fooTable = this.MobileService.GetSyncTable<Foo>();

4)次に、データをプッシュおよびプルして、最新の変更があることを確認します。

await this.MobileService.SyncContext.PushAsync();
await this.saleItemsTable.PullAsync("allFoos", fooTable.CreateQuery());

https://Azure.Microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started-offline-data/

5

Symmetricds もご覧になることをお勧めします。 Androidシステムで使用できるSQLiteレプリケーションライブラリです。これを使用してクライアントとサーバーのデータベースを同期できます。また、クライアントごとにサーバー上に個別のデータベースを用意することをお勧めします。 1つのmysqlデータベース内のすべてのユーザーの最良のアイデアとは限りません特にユーザーデータが急速に成長する場合。

0