概要
コンシステントハッシュがどのように機能するかについてブログを書きました。ここでは、これらの元の質問に答えるために、以下に簡単な要約を示します。
コンシステントハッシュは、データ分割の目的でより一般的に使用され、通常、次のようなコンポーネントで見られます。
質問に答えるために、以下はカバーします
- 使い方
- サーバーノードを追加/検索/削除する方法
- それを実装する方法
- コンシステントハッシュに代わるものはありますか?
ここで簡単な例を使用してみましょう。ロードバランサーは、2つのオリジンノード(ロードバランサーの背後にあるサーバー)と同じハッシュリングサークル内の着信リクエストをマップします(ハッシュリングの範囲が[0,255]であるとします)。
初期状態
サーバーノードには、次のテーブルがあります。

ノードの検索
着信リクエストに対して、同じハッシュ関数を適用し、ハッシュコード= 120のリクエストのハッシュコードを取得すると仮定します。テーブルから、時計回りに次に近いノードが見つかるため、ノード2はこの場合のターゲットノード。
同様に、ハッシュコード=220のリクエストを受け取った場合はどうなりますか?ハッシュリングの範囲は円であるため、最初のノードを返します。
ノードの追加
次に、クラスターにもう1つのノードノード3(ハッシュコード150)を追加すると、テーブルが次のように更新されます。

次に、[ノードの検索]セクションで同じアルゴリズムを使用して、次に近いノードを検索します。たとえば、ハッシュコード= 120のリクエストは、ノード3にルーティングされます。
ノードを削除
削除も簡単です。テーブルからエントリ<node、hashcode>を削除するだけです。たとえば、node-1を削除すると、テーブルは次のように更新されます。

次に、すべてのリクエストは次のようになります。
- [201、255]および[0、150]のハッシュコードはノード3にルーティングされます
- [151、200]のハッシュコードはノード2にルーティングされます
実装
以下は、Javaに非常によく似た単純なc ++バージョン(仮想ノードが有効になっている)です。
#define HASH_RING_SZ 256
struct Node {
int id_;
int repl_;
int hashCode_;
Node(int id, int replica) : id_(id), repl_(replica) {
hashCode_ =
hash<string>{} (to_string(id_) + "_" + to_string(repl_)) % HASH_RING_SZ;
}
};
class ConsistentHashing {
private:
unordered_map<int/*nodeId*/, vector<Node*>> id2node;
map<int/*hash code*/, Node*> ring;
public:
ConsistentHashing() {}
// Allow dynamically assign the node replicas
// O(Rlog(RN)) time
void addNode(int id, int replica) {
for (int i = 0; i < replica; i++) {
Node* repl = new Node(id, replica);
id2node[id].push_back(repl);
ring.insert({node->hashCode_, repl});
}
}
// O(Rlog(RN)) time
void removeNode(int id) {
auto repls = id2node[id];
if (repls.empty()) return;
for (auto* repl : repls) {
ring.erase(repl->hashCode_);
}
id2node.erase(id);
}
// Return the nodeId
// O(log(RN)) time
int findNode(const string& key) {
int h = hash<string>{}(key) % HASH_RING_SZ;
auto it = ring.lower_bound(h);
if (it == ring.end()) it == ring.begin();
return it->second->id;
}
};
代替案
私が質問を正しく理解している場合、質問は、データ分割の目的でコンシステントハッシュの代替案を尋ねることです。実際にはたくさんありますが、実際のユースケースに応じて、次のようなさまざまなアプローチを選択できます。
- ランダム
- ラウンドロビン
- 加重ラウンドロビン
- Modハッシュ
- コンシステントハッシュ
- 加重(動的)コンシステントハッシュ
- 範囲ベース
- リストベース
- 辞書ベース
- ..。
特に負荷分散ドメインでは、次のようなアプローチもあります。
上記のすべてのアプローチには独自の長所と短所があり、最善の解決策はありません。それに応じてトレードオフを行う必要があります。
最後
上記のように、元の質問の簡単な要約をさらに読むために:
- コンシステントハッシュアンバランスの問題
- 雪のクラッシュの問題
- 仮想ノードの概念
- レプリカ番号を微調整する方法
私はすでにブログでそれらをカバーしました、以下はショートカットです:
楽しむ :)