memcachedのアトミック操作とカウンター

「Web、Caching、Memcached」に関する一連の投稿が続きます。 1回目2回目の投稿では、memcached、そのアーキテクチャ、可能なアプリケーション、キャッシュキーの選択、 memcachedクラスタリングについて説明しました。



今日は以下についてお話します:



次の投稿では、キャッシュを同時に再構築する問題に専念します。





memcachedのアトミック操作



そのため、すべての単一memcachedリクエストはアトミックです(マルチスレッドの場合、シングルスレッドおよび正しい内部ロックのため)。 これは、getリクエストを実行すると、誰かがキャッシュに書き込んだときにキー値を取得しますが、2つのレコードの混合ではないことを意味します。 ただし、各操作は独立しており、たとえば、複数の並列プロセスからの競合アクセス状況でのこのような手順の正確性を保証することはできません。

  1. キー "x"の値を取得します( $x = get x



    )。
  2. 変数の値を1つ増やします( $x = $x + 1



    )。
  3. 新しい変数値をmemcachedに書き込む( set x = $x



    )。


このコードが複数のフロントエンドによって同時に実行された場合、キーxの値は意図したとおりn回増加せず、より低い値(従来の競合状態競合状態 )になることがあります。 もちろん、このアプローチは私たちには受け入れられません。 この状況に対する古典的な答えは、同期プリミティブ(セマフォ、ミューテックスなど)の使用ですが、memcachedにはありません。 この問題の別の解決策は、非原子のget / setシーケンスを置き換えるより複雑な操作を実装することです。



Memcachedには、この問題を解決するための2つの操作があります: incr



/ decr



(インクリメントとデクリメント)。 これらは、memcachedに存在するキーの整数値のアトミックな増加(またはそれに応じて減少)を提供します。 追加の操作もアトミックです: append



/ prepend



を使用すると、キー値の先頭または末尾にデータをadd



できます。また、キー値が以前に存在しなかった場合にのみキー値を設定できるadd



およびreplace



操作はアトミックと見なすことができます。または、逆に、既存のキーの値を置き換えます。 アトミック操作の別のバリアントについては、memcachedを使用したロックの実装に関するセクションで説明します。

さらに、memcachedのロックはきめ細かくする必要があります。つまり、サーバーの主なタスクは可能な限り多くの並列プロセスに効果的なキャッシュアクセスを提供することであるため、できるだけ少ないオブジェクトに影響を与える必要があります。



memcachedのカウンター



Memcachedは、バックエンドからのサンプルのキャッシュの保存、ユーザーセッションの保存(記事の冒頭で言及)だけでなく、memcachedなしでは解決が難しいタスクにも使用できます-リアルタイムカウンターの実装。 つまり、特定の時点でのカウンターの現在の値を表示するタスクに直面しています。「リアルタイム」の要件を折りたたむと、これはログの収集とその後の累積ログの分析によって実現できます。

そのようなカウンターのいくつかの例、それらの実装方法、および可能な問題を見てみましょう。



カウンターを見る



プロジェクトにいくつかのオブジェクト(たとえば、写真、ビデオ、記事など)があり、それらのオブジェクトのビューの数をリアルタイムで表示する必要があるとします。 カウンターはビューごとに増加するはずです。 最も簡単なオプションは、データベースが機能しないたびにフィールドを更新することです。 多くのビューがあり、データベースはこのような負荷に耐えられません。 表示統計、その蓄積、および定期的な分析の正確で正確な収集を実装できます。これは、データベース内のカウンターの更新で終わります(たとえば、1時間に1回)。 ただし、現在のビュー数を表示するタスクは残ります。



次の可能な解決策を検討してください。 オブジェクトを表示するときのフロントエンドは、memcachedのカウンターキーの名前を形成し、このキーで増分操作(増分)を実行しようとします。 実行が成功した場合、これは対応するキーがmemcachedにあることを意味し、ビューをカウントし、ユーザーに表示できる新しいカウンター値( incr



操作の結果)も取得しました。 incr



操作でエラーが返された場合、カウンターキーは現在memcachedにありません。データベースからのビューの数を初期値として選択し、それを1つ増やし、set操作を実行して新しいカウンター値を設定できます。 後続のスキャンでは、キーはすでにmemcachedにあり、incrを使用してその値を単純に増やします。



上記のスキームは完全に正しいわけではないことに注意してください:競合状態があります。 2つのフロントエンドが同時にカウンターにアクセスし、同時にその不在を検出し、2つのセット操作を行うと、1つのビューが失われます。 統計を蓄積するプロセスにより正しい値が復元されるため、これはあまり重要ではないと見なすことができます。 必要に応じて、memcachedでロックを使用できます。これについては以下で説明します。 または、 add



操作でカウンターの初期化を実装し、その結果を処理します。



オンラインカウンター



memcachedまたは同様のソリューションなしではほとんど実装できない別の種類のカウンターがあります。それはオンラインカウンターです。 このようなカウンタは多数のサイトで見られますが、まず、「オンライン」とは正確に何を意味するのかを判断する必要があります。 過去5分間にサイトにアクセスしたユニークセッション(ユーザー)の数を計算するとします。 このセッションでの5分間のユーザーのトリートメントの一意性は、セッションで最後にカウントされたトリートメントの時間を保存することで追跡できます。5分以上経過した場合、これは新しい(ユニークな)トリートメントを意味します。







したがって、memcachedに名前が付いている6つのキー、たとえばc_0



c_1



c_2



、...、 c_5



ます。 現在の変数キーは、現在の分を6で割った余りに等しい数のカウンターを考慮します(図ではこれはキーc_4



)。 incr操作の助けを借りて増加させ、各セッションを5分間ユニークに対応させます。 incr



がエラーを返した場合(カウンターがまだない場合)、setを使用してその値を1にset



、必ず6分の有効期間を指定してください。 オンラインユーザーのカウンターの値は、現在のキーを除くすべてのキーの合計と見なされます(図では、これらはキーc_0



c_1



c_2



c_3



およびc_5



)。



次の分c_5



と、 c_5



キーは現在の可変キーになりますが、その前の値は消えます(6分前に同じ6分のライフタイムで作成されたため)。 カウンター値は、キーc _0



合計になります。 _4



計算されたばかりのキー値は、表示されたカウンター値で既に考慮され始めます。



このようなカウンターは、より少ないキーで構築できます。 このスキームで可能な最小値は2つのキーです。1つは更新され、もう1つの値が表示され、5分後にカウンターが交換され、更新されたキーはリセットされます。 多くのキーを備えた特定のスキームでは、特定の「スムージング」が提供され、訪問者が急激に流入または流出した場合にカウンターをよりスムーズに変更できます。



All Articles