既存の SimpleDB API は、分散カウンターになるのに自然に適しているわけではありません。しかし、それは確かに行うことができます。
SimpleDB 内で厳密に動作させるには、2 つの方法があります。クリーンアップに cron ジョブなどを必要とする簡単な方法。または、それが進むにつれてきれいになる、はるかに複雑なテクニック。
簡単な方法
簡単な方法は、「ヒット」ごとに異なるアイテムを作成することです。キーである単一の属性を使用します。カウントを使用してドメインをすばやく簡単にポンピングします。カウントをフェッチする必要がある場合 (おそらく、はるかに少ない頻度で)、クエリを発行する必要があります。
SELECT count(*) FROM domain WHERE key='myKey'
もちろん、これによりドメインが無制限に成長し、クエリの実行に時間がかかるようになります。解決策は、キーごとにこれまでに収集されたすべてのカウントをロールアップする要約レコードです。これは、キー {summary='myKey'} の属性と、ミリ秒単位の粒度を持つ「最終更新」タイムスタンプを持つ単なるアイテムです。これには、「ヒット」アイテムに「timestamp」属性を追加することも必要です。要約レコードは同じドメインにある必要はありません。実際、セットアップによっては、別のドメインに保持するのが最適な場合があります。どちらの方法でも、キーを itemName として使用し、SELECT を実行する代わりに GetAttributes を使用できます。
カウントの取得は 2 段階のプロセスです。要約レコードを取得し、要約レコードの「最終更新」時刻よりも厳密に大きい「タイムスタンプ」を照会して、2 つのカウントを合計する必要があります。
SELECT count(*) FROM domain WHERE key='myKey' AND timestamp > '...'
また、要約レコードを定期的に更新する方法も必要になります。これは、スケジュールに従って (1 時間ごとに) 実行することも、他の基準に基づいて動的に実行することもできます (たとえば、クエリが複数のページを返すたびに通常の処理中に実行するなど)。サマリー レコードを更新するときは、結果整合性ウィンドウを過ぎた十分に過去の時間に基づいていることを確認してください。1分は安全以上です。
このソリューションは同時更新に直面しても機能します。これは、多数の要約レコードが同時に書き込まれたとしても、カウントと「最終更新」属性がそれぞれと一致するため、それらはすべて正しく、どちらが勝っても正しいままであるためです。他の。
これは、ヒット レコードで要約レコードを保持している場合でも、複数のドメイン間でうまく機能します。すべてのドメインから同時に要約レコードを取得し、すべてのドメインにクエリを並行して発行できます。これを行う理由は、1 つのドメインから取得できるよりも高いスループットがキーに必要な場合です。
これはキャッシングでうまく機能します。キャッシュに障害が発生した場合、信頼できるバックアップがあります。
誰かが戻って、古い「タイムスタンプ」値を持つレコードを編集/削除/追加したい時が来るでしょう。その時点で (そのドメインの) サマリー レコードを更新する必要があります。そうしないと、そのサマリーを再計算するまでカウントがオフになります。
これにより、一貫性ウィンドウ内で現在表示可能なデータと同期しているカウントが得られます。これは、ミリ秒まで正確なカウントを提供しません。
ハードウェイ
もう 1 つの方法は、通常の読み取り - インクリメント - ストア メカニズムを実行するだけでなく、値とともにバージョン番号を含む複合値を書き込むことです。使用するバージョン番号は、更新する値のバージョン番号よりも 1 大きくなります。
get(key) は属性 value="Ver015 Count089" を返します
ここでは、バージョン 15 として保存された 89 のカウントを取得します。更新を行うときは、次のように値を書き込みます。
put(key, value="Ver016 Count090")
以前の値は削除されず、lamport クロックを連想させる更新の監査証跡が作成されます。
これには、いくつかの追加作業が必要です。
- GET を実行するたびに競合を特定して解決する機能
- 単純なバージョン番号は機能しません。少なくともミリ秒単位の解像度のタイムスタンプと、場合によってはプロセス ID も含める必要があります。
- 実際には、競合をより簡単に解決するために、値に現在のバージョン番号と更新の基になっている値のバージョン番号を含める必要があります。
- 1 つの項目に無限の監査証跡を保持することはできないため、古い値に対して削除を発行する必要があります。
この手法で得られるものは、分岐更新のツリーのようなものです。1 つの値があり、突然複数の更新が発生し、同じ古い値に基づいて一連の更新が行われますが、それらは互いに認識していません。
GET 時に競合を解決すると言うとき、アイテムを読み取って値が次のようになる場合を意味します。
11 --- 12
/
10 --- 11
\
11
実際の値が 14 であることを把握できる必要があります。更新する値のバージョンを新しい値ごとに含めると、これが可能になります。
ロケット科学であってはならない
単純なカウンターだけが必要な場合:これはやり過ぎです。単純なカウンターを作るのはロケット科学であってはなりません。これが、SimpleDB が単純なカウンターを作成するための最良の選択ではない可能性がある理由です。
これが唯一の方法ではありませんが、実際にロックする代わりに SimpleDB ソリューションを実装する場合は、これらのほとんどを行う必要があります。
誤解しないでください。ロックがなく、このカウンターを同時に使用できるプロセス数の制限が約 100 であるため、私は実際にこの方法が好きです (アイテムの属性数の制限のため)。また、いくつかの変更を加えることで、100 を超えることもできます。
ノート
しかし、これらすべての実装の詳細が隠されていて、increment(key) を呼び出すだけでよい場合は、まったく複雑ではありません。SimpleDB では、クライアント ライブラリが複雑なものをシンプルにするための鍵となります。しかし、現在、この機能を実装する公に利用可能なライブラリはありません (私の知る限り)。