今日は以下についてお話します:
- キャッシングキーの選択
- memcachedクラスタリングおよびキー配布アルゴリズム。
次の投稿では、 memcachedの操作とカウンターの原子性について説明します。
キャッシングキー
キャッシングにmemcachedを使用することが適切なソリューションであることをすでに確認してみましょう。 直面する最初のタスクは、各キャッシュのキーの選択です。 memcachedのキーは、限られた長さの文字列で、限られた文字セットで構成されています(たとえば、スペースは禁止されています)。 キャッシュキーには次のプロパティが必要です。
- キャッシュするサンプルのパラメーターを変更する場合、キャッシュキーを変更する必要があります(新しいパラメーターで古いキャッシュに「落ちない」ように)。
- キーは、サンプリングパラメータによって明確に決定する必要があります。 同じサンプルに対してキャッシュキーは1つだけにしてください。そうしないと、キャッシュプロセスの効率が低下する危険があります。
もちろん、各サンプルのキーを個別に作成することもできます。たとえば、ID 158のユーザー情報を取得する
'friends_192_public_sorted_online'
や、ID 192のユーザーの友人の
'friends_192_public_sorted_online'
を公開できます。 このようなアプローチには、エラーと上記で作成された条件への非準拠が伴います。
次のオプション(PHPの例)を使用できます:データベースへのすべての呼び出しが通過するコードにポイントがあり、すべての呼び出しが一部の
$options
構造に完全に記述されている(すべての要求パラメーターを含む)場合、次のキーを使用できます:
$key = md5(serialize($options))
このようなキーは間違いなく最初の条件を満たします(
$options
が変更されると、
$key
は必ず変更されます)が、$オプションのすべてのデータ型を「標準的に」使用すると、2番目の条件も満たされます。 数字の
1
代わりに文字列
"1"
許可しないでください(PHPではこのような2つの値は同じですが、シリアル化された表現は異なります)。
md5
関数は、データを「圧縮」するために使用されます。memcachedキーには長さの制限があり、シリアル化されたビューが長すぎる可能性があります。
Memcachedクラスタリング
単一のmemcachedサーバーの代わりに、このようなサーバーのクラスターを使用して負荷を分散し、フォールトトレランスを実現します。 クラスターに含まれるサーバーは、異なる量のメモリで構成でき、合計キャッシュサイズは、クラスターのすべてのmemcachedメンバーのキャッシュサイズの合計に等しくなります。 memcachedプロセスは、プロセッサの使用率が低く、ネットワークが制限までロードされていないサーバー(ファイルサーバーなど)で開始できます。 プロセッサの負荷が高いと、memcachedは要求に十分に迅速に応答できない可能性があり、サービスの低下につながります。
クラスターで作業する場合、キーはサーバー間で分散されます。つまり、各サーバーはプロジェクトキーの合計配列の一部を処理します。 フォールトトレランスは、サーバーの1つに障害が発生した場合、キーが残りのクラスターサーバーに再配布されるという事実に基づいています。 もちろん、この場合、障害が発生したサーバーのコンテンツは失われます(「キーの損失」セクションを参照)。 必要に応じて、重要なキーを1つのサーバーではなく複数のサーバーに保存できるため、ストレージの冗長性によるサーバークラッシュの影響を最小限に抑えることができます。
クラスタリングでは、キー配布の問題が重要になります。サーバー間でキーを最も効率的に配布する方法です。 これを行うには、キー配布機能を決定する必要があります。キー配布機能は、キーによって保管先のサーバー番号(または、ストレージが冗長で発生する場合はサーバー番号)を返します。
歴史的に、最初の分布関数はモジュール関数でした:
f() = crc32() % _
このような機能により、サーバー間でキーが均一に分散されますが、memcachedクラスターを再構成すると問題が発生します。サーバーの数を変更すると、サーバー間でキーの大部分が移動し、キーの大部分が失われることになります。
この機能の代替手段は、一貫したハッシュメカニズムです。これは、クラスターを再構成するときに、サーバー全体でキーの位置を保持します。 このアプローチは、2007年4月にLast.fm開発者によってmemcachedクライアントに最初に実装されました。
アルゴリズムの本質は次のとおりです。0から2 32までの整数のセットを考え、数値軸をリングに「ねじり」ます(0と2 32を接着します)。 memcachedサーバーのプールから各サーバーに、リング上の番号を関連付けます(左側の図、サーバーA、B、C)。 キーは同じ範囲の数字にハッシュされます(図の青い点1〜4)。キーを保存するサーバーとして、時計回りにキーポイントに最も近いポイントにあるサーバーを選択します。 サーバーがプールから削除されるか、プールに追加されると、サーバーポイントが軸上に表示または非表示になり、その結果、キーの一部のみが別のサーバーに移動されます。 右側の図2は、サーバーCがサーバープールから削除され、新しいサーバーDが追加されたときの状況を示しています。キー1と2がサーバーへのバインドを変更せず、キー3と4が他のサーバーに移動したことがわかります。 実際、軸上の100〜200ポイントが1つのサーバーに割り当てられ(プール内の重みに比例)、構成が変更された場合にサーバー全体でキーの分散の均一性が向上します。
このアルゴリズムは、さまざまなプログラミング言語の多くのmemcachedクライアントに実装されていますが、実装の詳細が異なる場合があり、ハッシュの非互換性につながります。 このため、さまざまなプログラミング言語からmemcachedサーバーの同じプールにアクセスする場合、一貫したハッシュを使用するのは不便です。 crc32とモジュールを使用した最も単純なアルゴリズムは、すべての言語のすべてのクライアントに同じ方法で実装され、サーバー上で同じキーハッシュを保証します。 したがって、異なるプログラミング言語のさまざまなクライアントからmemcachedにアクセスする必要がない場合、一貫したハッシュを使用するアプローチがより魅力的に見えます。