ゴール
1 回限りのトークンのテーブルがあります。多くても 1 つのスレッドが特定の行を読み取ることができる必要があります。競合状態が発生して行がまったく読み取れない可能性が低い場合は許容されます。
どうして
OAuth2 で認証コード フローを実装しています。サーバーは、一意の ID を持つ「認証コード」付与トークンを作成し、それをクライアントに渡します。クライアントはすぐに戻ってきて、認証コードを実際のアクセス トークンに引き換えようとします。この償還は最大 1 回行う必要があります。攻撃者が認証コードを手に入れたが、クライアントが最初にそれを引き換えた場合、攻撃者もそれを引き換えることができてはなりません。
認証コードは最大 10 分後に期限切れになります。償還を確認するために有効期限のタイムスタンプ列を保存していますが、ガベージ コレクションには Cassandra の TTL 機能 (列の有効期限) も使用しています。
ここでのすべての操作は、LOCAL_QUORUM で実行されます。各認証コードは、認証コード値に等しいキーを持つ行で表されます。
満足できない/壊れた解決策
- カウンターコラム
- 認証コード引き換え用のカウンター列を維持します。スレッドが認証コードを引き換えようとすると、最初にカウンター列の認証コードの行がインクリメントされ、次に認証コードの列が読み取られます。カウントが 1 より大きい場合は拒否します。競合状態では、両方のスレッドが拒否される可能性があります。
- 妥当性: これはすべて失敗するエラーのみで正しく動作すると思います。
- 欠点: Cassandraはカウンター列のTTL をサポートしていないため、リーパー プロセスを実行する必要があります。
- ディブ
- 「dibs」と呼ばれる文字列列を維持します。スレッドが認証コードを引き換えようとすると、一意の ID が dibs 列に書き込まれ、列が読み取られます。dibs 値が一致しなくなった場合は拒否します。
- 有効性: いいえ。スレッド 1 は、書き込み、読み取り、受け入れを行います。スレッド 2 は書き込み、読み取り、受け入れます。これは、他のスレッドのアクションの後に発生する可能性があるため、読み取りの後に削除または 2 番目の書き込みを追加するだけでは修正できません。
可能な解決策
ランポートのベーカリー アルゴリズムは疑わしいほど適切に見えますが、おそらくやり過ぎです。
質問
協調的な単一リーダー ロックのカウンター列に行き詰っていますか?