0

次のような JSON オブジェクトを処理する共同 Web アプリケーションがあります。

var post = {
  id: 123,
  title: 'Sterling Archer',    
  comments: [
    {text: 'Comment text', tags: ['tag1', 'tag2', 'tag3']},
    {text: 'Comment test', tags: ['tag2', 'tag5']}
  ]  
};

私のアプローチは、JSON ドキュメントにパッチを適用するためのjsonpatchライブラリでrfc6902 (JSONPatch) 仕様を使用することです。このようなドキュメントはすべて MongoDB データベースに保存されます。ご存知のように、最後のドキュメントは頻繁に書き込むと非常に遅くなります。

より高速で高負荷のアプリケーションを取得するために、次のようなパッチ操作のキューとして redis を使用します。

{ "op": "add", "path": "/comments/2", "value":  {text: 'Comment test3', tags: ['tag4']}" }

そのようなすべてのパッチ操作をキューに保存し、真夜中に cron スクリプトを実行してすべてのパッチを取得し、完全なドキュメントを作成して MongoDB データベースで更新します。

次のような破損したパッチの場合、どうすればよいかまだわかりません。

{ "op": "add", "path": "/comments/0/tags/5", "value": 'tag4'}

tags配列の長さが 3 しかないため、上記のパッチは上記のドキュメントには適用されません(公式ドキュメントhttps://www.rfc-editor.org/rfc/rfc6902#page-5によると) 。

 The specified index MUST NOT be greater than the number of elements in the array.

そのため、ユーザーがオンラインの場合、パッチ操作が redis キューに保存されるためエラーは発生しませんが、翌日、cron スクリプトに適用されていない壊れたパッチが原因で壊れたドキュメントが表示されます。

私の質問は、redis キューに保存されているすべてのパッチが正しく、プライマリ ドキュメントが破損していないことをどのように保証できるのでしょうか?

4

2 に答える 2

3

一貫性が失われる可能性のあるシステムと同様に、競合を早期に発見し、競合が発生する可能性を減らしたい場合は、できるだけ早くパッチを適用できるようにする必要があります。更新されたデータをできるだけ早く他のクライアントに通知しない場合 (そして、他のクライアントがアクセスできる共有データを更新するために CRON が実行されるのを待っている場合) は、これが主な問題である可能性があります。

他の人が尋ねたように、そもそも「悪い」パッチがどのようにして操作キューに入ったのかを理解することが重要です。ここに私の観点からのいくつかの推測があります:

  1. ユーザーが適用した操作が変換中に失われました。どのように?わかりませんが、それは矛盾を説明するでしょう。
  2. 操作が正しい順序で適用されていません。どのように?知らない。オフにするコードはありません。

実行するコードはありませんが、暗闇の中でショットを撮り、後者のポイントを分析するのに役立ちます. 最初に分析する必要があるのは、「共有」リソースの更新で発生する可能性のあるさまざまなシナリオです。最終的に一貫性が必要なシステムでは、次の点に注意することが重要です。

  1. 操作の順序。
  2. 紛争にどのように対処するか。

後者は本当にあなた次第であり、クライアントが見る「真実」を更新するための優れた通知/メッセージングシステムが必要になります.

シナリオ 1

ユーザー A は操作 1 と 2 を適用します。サーバー上でドキュメントが更新され、ユーザー B に通知されます。ユーザー B は操作 3 と 4 を適用しようとしましたが、これらの操作 (この順序で) は操作 1 と 2 と競合しません。万事順調です。これは良い状況です。

シナリオ 2

ユーザー A は操作 1 と 2 を適用します。ユーザー B は操作 3 と 4 を適用します。

ユーザーごとにアトミックに操作を適用すると、次のキューを取得できます。

[1,2,3,4] [3,4,1,2]

競合が発生した場合は、「誰が最初にそこに到達したか」(または使用したいその他の重み付けセマンティクス) に基づいて、ユーザー A またはユーザー B のいずれかに通知する必要があります。繰り返しますが、競合にどう対処するかはあなた次第です。ベクトルクロックについて読んだことがない場合は、読んでください。

ユーザーごとに操作をアトミックに適用しない場合、次のキューを取得できます。

[1,2,3,4] [3,4,1,2] [1,3,2,4] [3,1,4,2] [3,1,2,4] [1,3, 4,2]

ご覧のとおり、ユーザーごとのアトミックな更新を控えると、更新の組み合わせが増えるため、競合が発生する可能性が高くなります。操作がユーザーごとにアトミックにキューに追加されていることを確認してください。

まとめ

覚えておくべき重要事項:

  1. キューへの更新がユーザーごとにアトミックに適用されるようにします。
  2. 異なるクライアントからの複数のミューテーションから生じる共有リソースの複数のバージョンをどのように処理するかを考えてください (繰り返しますが、ベクトル クロックについて読むことをお勧めします)。
  3. 複数のクライアントがリアルタイムで cron ジョブとしてアクセスする可能性のある共有リソースを更新しないでください。
  4. 解決できない対立がある場合は、それをどのように処理するかを考えてください。
  5. ポイント 3 の結果として、クライアントが更新されたリソースを迅速に取得できるように、通知システムを用意する必要があります。ポイント 4 の結果として、更新で問題が発生したことをクライアントに伝えることを含めることを選択できます。頭のてっぺんに浮かんだのは、pub/sub 機能を備えた Redis を既に使用しているということです。

編集

Google ドキュメントは、競合の解決を変換で処理しているようです。つまり、文字/行全体をシフトして、すべての操作のハイブリッド アプリケーションに道を譲ることです: https://drive.googleblog.com/2010/09/whats-different-about-new-google-docs_22.html

前に述べたように、すべてはアプリケーション/製品自体とそのユース ケースによって決定される必要がある、独自の競合をどのように処理するか次第です。

于 2014-09-19T11:32:02.010 に答える