簡単な紹介
ジャンプ一貫したハッシュ一貫したハッシュアルゴリズムそのゼロメモリ消費量、均一な分布、急速な、そして唯一の5行。
このアルゴリズムは、サブシャードにおける分散ストレージシステムでの使用に適しています。
このアルゴリズムの著者は、Googleのジョン・ランピングとエリックVeach、の元の論文であるhttp://arxiv.org/ftp/arxiv/papers/1406/1406.2294.pdf
完全なコード:
int32_t JumpConsistentHash(uint64_t key, int32_t num_buckets) {
int64_t b = -1, j = 0;
while (j < num_buckets) {
b = j;
key = key * 2862933555777941757ULL + 1;
j = (b + 1) * (double(1LL << 31) / double((key >> 33) + 1));
}
return b;
}
64ビット入力キーの数、およびタブ(一般サーバの数に相当する)、バケット番号が出力されます。
の原理を説明します:
翻訳する、紙の導出に応じバイロン以下:
ジャンプ一貫したハッシュ設計目標は以下のとおりです。
- バランスは、オブジェクトを均一すべてのバケットに分散されています。
- 樽の数の変化、新しいバレルバレルに古いからいくつかのオブジェクトを移動するだけの必要性が、他のモバイルをしない単調、。
:デザインのアイデアは、一貫したハッシュがジャンプしたときにその変更を出力する必要が変化し、多くのバケツを計算します。
私たちは一歩一歩を考えてみましょう:
- 注CH(キー、num_buckets)はnum_bucketsハッシュ関数です。
- 場合num_buckets = 1、唯一のバケツので、それは明らかである、任意のkについて、そこCH(K、1)== 0。
- = 2 num_bucketsは、ハッシュの結果が均一に維持するために、結果CH(K、2)結果の割合が1/2 0 1/2 1への遷移に維持されなければならない場合。
- 一般的な規則はこのように、:nは1〜N + num_buckets変化、結果CH(K、N + 1)、結果は1ながらN /(N + 1)の割合は、変化しないままでなければなりません/ (N + 1)N + 1にジャンプ。
したがって、我々はジャンプするかどうかを毎回決定する乱数ジェネレータを使用し、乱数生成器のこの状態は唯一のキーに依存させることができます。我々は、次の予備的なコードを取得します:
int ch(int key, int num_buckets) {
random.seed(key) ;
int b = 0; // This will track ch(key, j +1) .
for (int j = 1; j < num_buckets; j ++) {
if (random.next() < 1.0/(j+1) ) b = j ;
}
return b;
}
明らかに、このアルゴリズムは、O(N)です。私たちは、ほとんどの場合、B = jがあり、jが増加し、下の方得る確率で実行されていないことがわかります。
乱数によると、Jの直接遷移を描き、それの時間の複雑さを軽減する方法はありますか?
[OK]を、確率論モードに切り替えるには、あなたの脳を入れてください。
私たちは、確率変数として見(キー、bum_bucketsを)CHことができます
バレル移行プロセスの数を追跡するためのアルゴリズムの上に、我々は、特定の結果の確率は、バレルの途中で何度も増加する、次いでB + 1からJ-1、Jであるという仮定の下で、結果は、遷移Bで覚え私たちは、ジャンプすることはできません。iが区間(B、J)である任意の整数の場合、jは、確率結果のように書くことができるです。
P(j> = 1)= P(CH(K、I)== CH(K、B + 1))
繰り返し何この確率は、繰り返しジャンプされていない、遷移増加場合CH(K、I)== CH(K、B + 1)は、浴槽中のB + 1からIへのプロセスを意味しない場合変更イベントの確率の積、これ:
P(j> = 1)= P(CH(K、B + 1)== CH(K、B + 2))* P(CH(K、B + 2)== CH(K、B + 3) )* P(CH(K、B + 3)== CH(K、B + 4))* ... * P(CH(K、I-1)== CH(K、I))
ではないので、単一のジャンプの確率は次のようになります。
P(CH(K、I)== CH(K、I + 1))= I /(I + 1)
だから、繰り返し確率をジャンプしません
P(j> = 1)=(B + 1)/(B + 2)*(B + 2)/(B + 3)* ... *(I-1)/ I
エントリの分子と分母が互いに打ち消し合う前と後に、我々が得ます:
P(j> = 1)=(B + 1)/ I
意味:Jの確率を> = iは(B + 1)/ I
この時点で、我々が取る[0,1]に均一に分布する乱数r、所定R <(B + 1)/ Iは、 Jが> = iは、
私がある<(B + 1)/ R、 Jを持っている必要があります> = I、そのことをので、この上限は、任意のIのために、I(B + 1)/ Rである
J =床((B + 1 )/ R)、 そして我々は、ランダムな番号を使用しますrはJを得ました。
したがって、コードように変更することができます。
int ch(int key, int num_buckets) {
random. seed(key) ;
int b = -1; // bucket number before the previous jump
int j = 0; // bucket number before the current jump
while(j<num_buckets){
b=j;
double r=random.next(); // 0<r<1.0
j = floor( (b+1) /r);
}
return b;
}
アルゴリズムの時間複雑さは、考慮され、各R 0.5が取られていると仮定することができ、各J = 2 * J、時間複雑度はO(ログ(N))であるので。
ここで一様擬似乱数発生器、合同乱数発生器線形64ビットで使用される紙を必要とします。
理解バイロン(フランスの切断とは異なり、内蔵された擬似乱数生成器を使用してジャンプ一貫したハッシュによるものであるハッシュキー、上の一貫性のあるハッシュをジャンプして、その後、それぞれのハッシュキーを行う必要はありません。ことが注目されます。したがって、関係なく、入力キーの配布結果、均一な擬似乱数生成器の保証)の分布の均一性。
指標の比較分析:
:紙切り出されデイビット・カルガー、クラシックと広くツール・ド・フランスで使用されることにより、論文の概念一貫したハッシュhttp://www.ra.ethz.ch/cdstore/www8/data/2181/pdf/pd1.pdf
カーガーは実現の2種類を提案しました。
- STDと "バージョンA"、::マップ<uint64_tを、int32_t>は、ハッシュバケットIDへのマッピングキーを表します。
- バイナリ検索して、ソートするベクトル<ペア<uint64_tを、int32_t >>メモリ、ベクターとの「バージョンB」、。
両方の実装の時間複雑度を求めるもO(ログ(N))であります
リングジャンプ一致ハッシュアルゴリズムを切断する、一貫性のあるハッシュ紙をジャンプしカーガーは以下の結果と比較しました。
1.キー分布均一性
次の表紙からの抜粋:
{%IMG /images/blog/jmp_consistent_hash_distribution.png%}
この列には、ジャンプ一貫したハッシュの均一性がより良いツール・ド・フランスよりもカットするために、標準偏差(標準誤差)から見ることができます。
そして明らかに、一貫性のあるハッシュ、膨張/収縮能力をジャンプ、ジャンプキーの数は、1の理論上の最小値を持っている/ N。
2.時間のかかります
以下、図コントラスト、K = 1000の時間のかかる紙です。
{%IMG /images/blog/jmp_consistent_hash_cpu.png%}
3.フットプリントの比較
もちろん、あなた自身の脳のサプリメント
4.初期化は、比較を消費
もちろん、あなた自身の脳のサプリメント
関連リンク
:上記のハッカーニュース議論https://news.ycombinator.com/item?id=8136408
このアルゴリズムは、グアバの内側Googleの最初のオープンソースのライブラリです:https://github.com/google/guava/blob/master/guava/src/com/google/common/hash/Hashing.java#L392