Azure テーブル ストレージにページ ビュー カウンターを実装しようとしています。2 人のユーザーが同時にページにアクセスし、PageViews の現在の値 = 100 の場合、更新操作後に PageViews = 102 であることが保証されますか?
4 に答える
「カウント」部分を再考することもできます。これを 2 ステップのプロセスに変えてみませんか?
ステップ 1 - ページ ビューの記録
誰かがページを表示するたびに、レコードがテーブルに追加されます (これを PageViews と呼びましょう)。これらのストアのいずれかに追加する情報は次のようになります。
- PartitionKey = ページ名
- RowKey = ランダム GUID
いくつかのビューの後、次のようになります。
- MyPage.aspx - someGuid
- MyPage.aspx - someGuid
- SomePage.aspx - someGuid
- MyPage.aspx - someGuid
ステップ 2 - ページ ビューのカウント
ここでやりたいことは、これらすべてのレコードを取得して数え、どこかでカウンターを増やし、すべてのレコードを削除することです。複数のワーカーが実行されていると仮定しましょう。両方のワーカーで、1 分から 10 分の間でランダムにループが実行されます。ワーカーの時間が経過するたびに、まだリースが取得されていない場合は BLOB のリースが取得されます (これは常に同じ BLOB である必要があります。AutoRenewLease を使用できます)。
ロックを取得した最初のワーカーは先に進み、カウントを行うことができます。
- PageViewRecordings テーブルまたはキャッシュからすべてのレコードを取得する
- ページごとにすべてのページ ビューをカウントする
- どこかでカウントを更新
- カウント時に考慮されたレコードを削除します
ここでの問題は、これを冪等プロセスに変えるのが非常に難しいということです。カウントと削除の間にインスタンスがクラッシュするとどうなりますか? ページ数は増えますが、項目は削除されていないため、次に処理するときに合計数に追加されます。
これが、私が次のことを提案する理由です。同じテーブル(PageViews) には、同じパーティション内の合計ページ ビューも記録されます。ただし、データは少し異なります (これは、合計カウントを保持するそのパーティション内の単一のレコードになります)。
- PartitionKey = ページ名
- RowKey = Guid.Empty (ランダム GUID を使用しないでください。これにより、記録されたページ ビューと合計カウントを保持するレコードの違いがわかります)。
- Count = 現在のページ ビュー数
Table Storage はスキーマレスであるため、これは完全に可能です。そして、なぜ私たちはこれをしているのですか?最大 100 個のエンティティを持つ同じテーブル + パーティションに制限すると、トランザクションが発生するためです。これで何ができるでしょうか?
- Take を使用して、そのテーブル + パーティションから 100 レコードを取得します。
- 最初に取得するレコードは「カウンター」レコードです。なんで?その行キーは Guid.Empty であり、並べ替えは辞書順であるため
- これらのレコードをカウントします (最初のレコードはページ ビューではなく、単なるカウンター プレースホルダーであるため -1)
- カウンター レコードの Count プロパティを更新する
- 99 (またはそれ以下) の他のレコードを削除する
- バッチを使用して変更を保存します。
- 残りのレコードが 1 つだけになるまで繰り返します (カウンター レコード)。
そして、X 分ごとに、ワーカーは BLOB にリースがないかどうかを確認し、リースを取得してプロセスを再起動します。
この答えは十分に明確ですか、それともコードを追加する必要がありますか?
Azure Websites を使用している場合は、Azure Queues と WebJobs も別のオプションです。私の 1 つのシナリオでは、実際にはシャーディング アプローチを採用し、Web ジョブに集計を定期的に更新させます。PartitionKey = User および RowKey = Page の UserPageViews の Azure テーブル ストレージ テーブル。同じユーザー ID を持つ 2 人の同時ユーザーは許可されません。
私も同じ質問で来ました。Azure python ライブラリを使用して、ロックの代わりにeTag
andを使用して単純なカウンターのインクリメントを開発しています。If-Match
基本的な考え方は、更新が特定の基準 (他の更新がこの実行中の更新に干渉しない) で正常に実行されるまで、カウンターの増加を再試行することです。更新のリクエストが多い場合は、シャーディングを呼び出す必要があります。
https://github.com/flyakite/simple-scalable-datastore/blob/master/datastore/azuretable.py