很晚了,一致性hash的理论不再多说,直接上我写的c++代码
代码功能:
1,初始化一些实际的server节点,每个server节点生成一堆虚拟节点
2,将所有的虚拟节点根据它的名字生成的hash key散布到一个环内
3,对新插入环内的元素(随机生成),计算它的hash key,然后在环中寻找大于等于它的虚拟节点,根据虚拟节点即可找到物理节点。随机生成很多歌元素,查看散布到各个节点的元素数量是否均衡。
代码一些特点:
对于server节点,只需要存储它的虚拟节点hash值以及与实际server名字的对应。对于新插入的元素,为了快速找到它所存放的位置(即大于等于它的hash值的虚拟节点),应该采用二分查找。 故而,虚拟节点使用map结构存储,底层是红黑树的实现,类似于二分,同时支持高效的插入删除。 当新的虚拟节点插入到环内,只需要移动很少量的元素到它上面。
还有chord算法要好好看看,还没有看。
#include<iostream>
#include <sstream>
#include <string>
#include <vector>
#include <list>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <iomanip>
#include <random>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cstdio>
using namespace std;
typedef unsigned long Key;
template <class T>
struct NodeHasher
{
template <class T>
Key operator() (const T& t){
return 0;
}
template <>
Key operator()<string> (const string& t){
return hash2((unsigned char*)t.c_str());
}
public:
//not a good hash function
static unsigned long hash(unsigned char *str)
{
unsigned long hash = 5381;
int c;
while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
static unsigned long hash2(unsigned char *str)
{
int p = 16777619;
int hash = (int)2166136261L;
int c;
while (c = *str++)
hash = (hash ^ c) * p;
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
// 如果算出来的值为负数则取其绝对值
if (hash < 0)
hash = abs(hash);
return hash;
}
};
template <class T>
class ConsistentHash
{
public:
ConsistentHash(int numberOfReplica = 150, bool isTest = false, int server=5): numOfReplicas(numberOfReplica){
if (isTest)
{
for (int c = 0; c < server; ++c)
{
addServer(to_string(c));
}
}
}
public:
void addServer(T node){
cout << "add real server:" << node << endl;
for (int i = 0; i < numOfReplicas; ++i)
{
Key k = NodeHasher<T>()(node + std::to_string(i));
if (i < 2)
cout << " virtual server: " << k << endl;
else if (i == 2)
cout << " ... " <<numOfReplicas<< endl;
circles.insert({ k, node });
}
}
void removeServer(T node){
cout << "remove real server:" << node << endl;
for (int i = 0; i < numOfReplicas; ++i)
{
Key k = NodeHasher<T>()(node+std::to_string(i));
auto it = circles.find(k);
if (it != circles.end()) circles.erase(it);
}
}
public:
T get(Key k){
auto it = circles.find(k);
if (it != circles.end()) return it->second;
it = circles.lower_bound(k);
return (it == circles.end()) ? circles.begin()->second : it->second;
}
public:
static void testIt(){
int number = 100000;
int server = 10;
int virutal_server = 150;
ConsistentHash chash(virutal_server, true, server);
struct {
void operator()(int number, ConsistentHash& chash) {
map<T, int> countNumMap;
std::random_device seed;
std::mt19937 gen(seed());
std::uniform_int_distribution<int> dist(0, LONG_MAX);
for (int i = 0; i < number; ++i)
{
Key k = dist(gen);
T node = chash.get(k);
countNumMap[node]++;
}
cout << "server numOfElems:" << endl;
for (auto it : countNumMap){
cout << it.first << " " << it.second << " " << std::setprecision(2) << it.second*1.0 / number << endl;
}
}
}show;
for (int i = 0; i < server; ++i)
{
show(number, chash);
chash.removeServer(std::to_string(i));
}
}
private:
int numOfReplicas;
map<Key, T> circles;
};
int main()
{
ConsistentHash<string>::testIt();
return 0;
}