2

問題:

アプリケーションの nosql データ ストアとして cassandra を使用する予定です。私が持っているユースケースの 1 つは、ユーザーの「残高」を更新することです。各ユーザーの残高がキー UID_balance として保存されているとします。アプリケーションで複数のユーザーの残高を更新したい場合、原子性をどのように処理すればよいでしょうか?

ある時点で、アプリケーションは基本的に次のことを行うと思います。

1. for each user u
2.    current_balance = read_users_balance(u);
3.    new_balance     = current_balance + delta_for_user(u);
4.    write_users_balance(u, new_balance);
5. end

ここで、いくつかの問題があります。

  1. cassandra への接続が中断され、コードが一部のユーザーの残高のみを更新する原因となる場合があります。
  2. ステップ 2 と 4 の間に、ユーザーの残高を更新する可能性のある別のプロセスが存在する可能性があり、古い残高を更新して、ユーザーの残高を「破損した」状態のままにします。

RDBMS は ACID プロパティを提供するため、これらの問題を解決しますが、Cassandra は提供しません。Cassandra はごく最近 (2012 年 10 月)、Atomic Batch の提供を開始しました。それがこの問題の正しい解決策であるかどうかはわかりません。

考えられる解決策:

これは私が友人とブレインストーミングしたものです。ユーザーの残高を実際に更新するのではなく、更新デルタを別のレコードに追加するレコードを作成します。例えば:

UID1_balance = {100}
UID1_deltas  = {10,20,-40}

現在の残高を取得するには、残高にデルタを適用するだけです。デルタをユーザーの残高に適用し、デルタ リストを削除するオフライン プロセスを使用できます。

このソリューションは機能し、破損状態の可能性を減らしますが、これはやり過ぎだと思います。この問題を解決するより良い方法はありますか?

4

3 に答える 3

6

論文「Building on Quicksand」を読むことをお勧めします。これにより、アカウントの観点から考えることができ、銀行口座の例をこのように参照することさえできます。注: チェイスとウェルズ・ファーゴはトランザクションで送金しないので、マクロ レベルと同じようにミクロ レベルで同じことを行う方法をその記事で説明しています ;)。

これは、cassandra 用の PlayOrm が作成されたときにも大いに役立ちました。現在 PlayOrm wiki にもパターン ページがあるためです。

于 2013-02-18T02:48:14.057 に答える
2

ロックがないため、最初の「読み取り変更書き込み」アプローチを Cassandra で機能させることはできません。Cassandra カウンターはこの問題を部分的に解決しますが、次の 2 か所で要件を満たすことができません。

  1. 複数のカウンターでアトミック バッチを実行することはできません。
  2. エラーが発生した場合、カウンターがインクリメントされたかどうかがわからないため、不正確な値になる可能性があります。

つまり、Cassandra 1.2 のアトミック バッチと組み合わせて、デルタを個別の列として格納するソリューションが、必要な保証を得る唯一の方法であることを意味します ( http://www.datastax.com/dev/blog/atomic-を参照)。 cassandra-1-2 のバッチ)。あなたのソリューションは、各カウンターが行に存在し、各デルタが列であるカウンターの実装に似ています。読み取るには、行の列のすべての値を合計します。

あなたが言うように、ここでの問題は、これらのデルタ リストが時間の経過とともに大きくなるため、ガベージを処理することです。更新があまり多くない場合は問題ありませんが、残高が頻繁に更新されると、読み取りが遅くなりすぎます。

「ガベージ コレクション」のオフライン プロセスは、デルタを読み取り、アトミックに削除し、値全体に対して 1 つのデルタを追加することで安全になります。アトミック バッチとシングル スレッド プロセスを使用すると、これを安全に行うことができます。

于 2013-02-17T10:48:30.810 に答える
2
  1. Richard が指摘したように、現時点で最善の方法は、多くのデルタを更新するアトミック バッチを使用することです。何か問題が発生した場合は、バッチを再生してください。

  2. 他に考えられる解決策は、ZooKeeper を調整および分散ロック サービスとして使用することです: http://ria101.wordpress.com/tag/zookeeper/

  3. 別の可能な解決策は、カウンターを使用することです。これを行う必要はありません

    your current_balance = read_users_balance(u);
    new_balance     = current_balance + delta_for_user(u);
    

    カウンターを使用すると、更新する前に残高を読み取る必要がないためです。http://www.datastax.com/dev/blog/whats-new-in-cassandra-0-8-part-2-counters

ただし、カウンターには問題があります。それらはべき等ではないため、インクリメント/デクリメントが成功したことを確認できない場合、オーバーカウントにつながる可能性があるため、そのカウンターをリプレイできません。

新しいカウンターはその問題を解決します。

于 2013-02-17T21:22:05.053 に答える