245

クライアントとサーバーの同期パターンがそこにあるに違いないと感じています。しかし、私はグーグルアップに完全に失敗しました。

状況は非常に単純です。サーバーは中央ノードであり、複数のクライアントが接続して同じデータを操作します。データはアトムに分割できます。競合が発生した場合は、サーバー上にあるものは何でも優先されます (ユーザーが競合を解決しないようにするため)。データが大量になる可能性があるため、部分的な同期が推奨されます。

そのような状況のパターン/グッドプラクティスはありますか、または何も知らない場合は、どのようなアプローチをとりますか?

以下は、私が今それを解決するために考えている方法です: データと並行して、変更ジャーナルが保持され、すべてのトランザクションにタイムスタンプが付けられます。クライアントが接続すると、前回のチェック以降のすべての変更を統合形式で受け取ります (サーバーはリストを調べて追加を削除し、その後に削除を行い、各アトムの更新をマージするなど)。ほら、私たちは最新です。

代わりに、各レコードの変更日を保持し、データの削除を実行する代わりに、それらを削除済みとしてマークするだけです。

何かご意見は?

4

7 に答える 7

93

分散変更管理がどのように機能するかを確認する必要があります。デルタの動作を管理するSVN、CVS、およびその他のリポジトリを見てください。

いくつかのユースケースがあります。

  • 変更を同期します。変更ログ(またはデルタ履歴)アプローチは、これに適しています。クライアントはデルタをサーバーに送信します。サーバーはデルタを統合してクライアントに配布します。これは典型的なケースです。データベースでは、これを「トランザクションレプリケーション」と呼んでいます。

  • クライアントが同期を失いました。バックアップ/復元を介して、またはバグが原因で。この場合、クライアントはデルタを経由せずにサーバーから現在の状態を取得する必要があります。これはマスターからディテールへのコピーであり、デルタとパフォーマンスはひどいものです。これは1回限りのことです。クライアントが壊れています。これを最適化しようとせず、信頼できるコピーを実装するだけです。

  • クライアントは疑わしいです。この場合、クライアントをサーバーと比較して、クライアントが最新であり、デルタが必要かどうかを判断する必要があります。

すべての変更に順番に番号を付けるというデータベース(およびSVN)のデザインパターンに従う必要があります。そうすれば、クライアントは同期を試みる前に簡単な要求(「どのリビジョンが必要ですか?」)を行うことができます。それでも、クエリ( "2149以降のすべてのデルタ")は、クライアントとサーバーが処理するのに非常に簡単です。

于 2009-01-05T13:47:02.237 に答える
35

チームの一員として、私はデータ同期を含むかなり多くのプロジェクトを行ったので、この質問に答えることができるはずです。

データの同期は非常に広い概念であり、議論することが多すぎます。それは、さまざまなアプローチの長所と短所をカバーしています。以下は、同期/非同期、クライアント/サーバー/ピアツーピアの 2 つの観点に基づく可能な分類の 1 つです。同期の実装は、これらの要因、データ モデルの複雑さ、転送および保存されるデータの量、およびその他の要件に大きく依存します。そのため、特定のケースごとに、アプリの要件を満たす最も単純な実装を優先して選択する必要があります。

既存の既製のソリューションのレビューに基づいて、同期の対象となるオブジェクトの粒度が異なるいくつかの主要な同期クラスを描くことができます。

  • ドキュメントまたはデータベース全体の同期は、Dropbox、Google ドライブ、Yandex.Disk などのクラウドベースのアプリケーションで使用されます。ユーザーがファイルを編集して保存すると、新しいファイル バージョンがクラウドに完全にアップロードされ、以前のコピーが上書きされます。競合が発生した場合は、両方のファイル バージョンが保存されるため、ユーザーはどちらのバージョンがより関連性が高いかを選択できます。
  • キーと値のペアの同期は、単純なデータ構造を持つアプリで使用できます。この場合、変数はアトミックであると見なされます。つまり、論理コンポーネントに分割されません。このオプションは、値とドキュメントの両方を完全に上書きできるため、ドキュメント全体の同期に似ています。ただし、ユーザーの観点から見ると、ドキュメントは多くの部分で構成される複雑なオブジェクトですが、キーと値のペアは短い文字列または数値にすぎません。したがって、この場合、値が最後に変更された場合は、より関連性の高い値を考慮して、競合解決のより単純な戦略を使用できます。
  • ツリーまたはグラフとして構造化されたデータの同期は、更新のたびにデータベース全体を送信するのに十分な量のデータがある、より高度なアプリケーションで使用されます。この場合、個々のオブジェクト、フィールド、または関係のレベルで競合を解決する必要があります。私たちは主にこのオプションに焦点を当てています。

したがって、トピックに関心のあるすべての人にとって非常に役立つと思われるこの記事に私たちの知識を取り入れました=>コアデータベースのiOSアプリでのデータ同期(http://blog.denivip.ru/index.php/2014/04 /data-syncing-in-core-data-based-ios-apps/?lang=en )

于 2016-03-16T06:22:00.467 に答える
29

本当に必要なのは操作変換(OT)です。これは、多くの場合、競合に対応することさえできます。

これはまだ活発な研究分野ですが、さまざまなOTアルゴリズムの実装があります。私はこのような研究に何年も携わっていますので、このルートに興味があるかどうかをお知らせください。関連するリソースをご紹介します。

于 2009-01-05T13:50:49.763 に答える
13

質問は明確ではありませんが、私があなたなら楽観的ロックを調べます。サーバーが各レコードに対して返すシーケンス番号を使用して実装できます。クライアントがレコードを保存しようとすると、サーバーから受信したシーケンス番号が含まれます。シーケンス番号が、更新を受信した時点でデータベースにあるものと一致する場合、更新が許可され、シーケンス番号がインクリメントされます。シーケンス番号が一致しない場合、更新は許可されません。

于 2009-01-05T13:32:22.437 に答える
12

私は約 8 年前にアプリ用にこのようなシステムを構築しましたが、アプリの使用が増えるにつれて進化した方法をいくつか共有できます。

まず、任意のデバイスからのすべての変更 (挿入、更新、または削除) を「履歴」テーブルに記録することから始めました。たとえば、誰かが「contact」テーブルの電話番号を変更した場合、システムは contact.phone フィールドを編集し、action=update、table=contact、field=phone、record=[ の履歴レコードも追加します。連絡先 ID]、値 = [新しい電話番号]。その後、デバイスが同期するたびに、前回の同期以降の履歴項目がダウンロードされ、ローカル データベースに適用されます。これは、前述の「トランザクション レプリケーション」パターンのように思えます。

1 つの問題は、アイテムが異なるデバイスで作成される可能性がある場合に、ID を一意に保つことです。これを始めたときは UUID について知らなかったので、自動インクリメント ID を使用し、デバイスからアップロードされた新しい ID をチェックし、競合があれば一意の ID に変更するために中央サーバーで実行される複雑なコードを書きました。ソース デバイスにローカル データベースの ID を変更するように指示します。新しいレコードの ID を変更するだけならそれほど悪くはありませんが、たとえば contact テーブルに新しいアイテムを作成し、次に event テーブルに新しい関連アイテムを作成すると、外部キーも必要になります。チェックして更新します。

最終的に、UUID でこれを回避できることを知りましたが、それまでにデータベースがかなり大きくなり、UUID を完全に実装するとパフォーマンスの問題が発生するのではないかと心配しました。そのため、完全な UUID を使用する代わりに、ランダムに生成された 8 文字の英数字キーを ID として使用するようにし、競合を処理するために既存のコードをそのまま残しました。私の現在の 8 文字のキーと UUID の 36 文字の間のどこかに、不必要に肥大化することなく競合を排除するスイート スポットがあるに違いありませんが、競合解決コードを既に持っているため、それを試すことは優先事項ではありませんでした。 .

次の問題は、履歴テーブルがデータベースの残りの部分よりも約 10 倍大きいことでした。これにより、ストレージのコストが高くなり、履歴テーブルのメンテナンスが苦痛になる可能性があります。そのテーブル全体を保持することで、ユーザーは以前の変更をロールバックできますが、やり過ぎのように感じ始めました。そのため、デバイスが最後にダウンロードした履歴項目が履歴テーブルに存在しなくなった場合、サーバーは最近の履歴項目を提供せず、代わりにすべてのデータを含むファイルを提供する同期プロセスにルーチンを追加しましたそのアカウント。次に、90 日以上経過した履歴項目を削除する cronjob を追加しました。これは、ユーザーが 90 日未満の変更を引き続きロールバックできることを意味し、少なくとも 90 日ごとに 1 回同期する場合、更新は以前と同様にインクリメンタルになります。ただし、90日以上待つと、

この変更により、履歴テーブルのサイズがほぼ 90% 縮小されたため、履歴テーブルを維持しても、データベースのサイズは 10 倍ではなく 2 倍になるだけです。このシステムのもう 1 つの利点は、必要に応じて履歴テーブルがなくても同期が機能することです。一時的にオフラインにするメンテナンスを行う必要がある場合などです。または、異なる価格帯のアカウントに対して異なるロールバック期間を提供することもできます。ダウンロードする変更が 90 日以上ある場合は、通常、完全なファイルの方が増分形式よりも効率的です。

今日からやり直す場合は、ID 競合チェックをスキップして、競合を排除するのに十分なキーの長さを目指します。念のため、何らかのエラー チェックを行います。(YouTube は 11 文字のランダム ID を使用しているようです。) 履歴テーブルと、最近の更新の増分ダウンロードまたは必要な場合の完全ダウンロードの組み合わせは、うまく機能しています。

于 2019-01-23T01:37:35.860 に答える