Consistent hashing is mainly used in large-scale high-availability distributed storage, especially for KV storage, such as memcaced, Redis cluster, compared to ordinary hash% N, but the advantage is that when adding or deleting nodes, the data migration will be relatively small, usually only partial jitter and migration. But its relative to the shortcomings of the hash%N data uniformity is certainly inferior to the hash%N especially the data key in a small range, easy to appear even phenomenon, but can be optimized by hash function, and increase the virtual node method to reduce the heterogeneity. Here is a C + + version of the consistent hash algorithm, where the M5 algorithm is the previous blog's Code
/********************************** function:consistent Hash Author:liuyi date:2015.10.31 viersion:1.0 ************* /#ifndef consistent_hash_h #define CONSISTENT_HASH_H #include <stdio.h> #include < string.h> #include <iostream> #include <set> #include <map> #include <string> #include <
vector> #include "md5.h" using namespace std;
inline unsigned int hash_fun (const char* key) {unsigned int hash = 0;
unsigned int seed = 131;
unsigned int len = strlen (key);
for (int i = 0; i < len; i++) {hash = (hash * seed) + key[i];
return hash;
typedef unsigned INT (*HASH_FUN_PTR) (const char*);
Class Consistent_hash {Public:consistent_hash () {m_virtual_node_mulriple = 1;
} ~consistent_hash () {m_node_map.clear (); BOOL Init (const vector<string>& node_vect, const int& virtual_node_mulriple, const HASH_FU
n_ptr& hash_func = hash_fun); size_t gEt_virtual_node_hash (const string& node, vector<unsigned int>& Virtual_node_hash_vec);
BOOL Add_node (const string& node);
BOOL Del_node (const string& node);
String Get_node (const string& key);
size_t Get_all_node (set<string>& nodes);
size_t Get_node_count ();
Private:int m_virtual_node_mulriple;
map<unsigned int, string> m_node_map;
Hash_fun_ptr M_hash_func;
};
#endif
/********************************** function:consistent Hash Author:liuyi date:2015.10.31 viersion:1.0 ************* /#include "CONSISTENT_HASH.H" bool Consistent_hash::init (const vector<string>& Node_ Vect, const int& virtual_node_mulriple, const hash_fun_ptr& hash_func) {if (Node_vect.empty ()) RET
Urn false;
M_virtual_node_mulriple = Virtual_node_mulriple;
M_hash_func = Hash_func;
for (size_t i = 0; i < node_vect.size (); i++) {vector<unsigned int> Virtual_node_hash_vec;
Get_virtual_node_hash (Node_vect[i], Virtual_node_hash_vec);
for (size_t j = 0; J < Virtual_node_hash_vec.size (); j + +) {M_node_map[virtual_node_hash_vec[j]] = node_vect[i];
} return true; } size_t Consistent_hash::get_virtual_node_hash (const string& node, vector<unsigned int>& Virtual_node_
Hash_vec) {virtual_node_hash_vec.clear ();
Virtual_node_hash_vec.reserve (m_virtual_node_mulriple*4+1); for (int i = 0; i< M_virtual_node_mulriple;
i++) {char virtual_node[256] = {0};
sprintf (Virtual_node, "%s#%u", Node.c_str (), i);
MD5 MD5;
Md5.update (Virtual_node);
Const unsigned char* digest = Md5.digest ();
for (int h = 0; h < 4; h++) {unsigned int hash_value = ((unsigned int) (DIGEST[3+H*4]&0XFF) << 24) | ((unsigned int) (DIGEST[2+H*4]&0XFF) << 16) | ((unsigned int) (DIGEST[1+H*4]&0XFF) << 8) |
(DIGEST[H*4]&0XFF);
Virtual_node_hash_vec.push_back (Hash_value);
} return Virtual_node_hash_vec.size ();
BOOL Consistent_hash::add_node (const string& node) {vector<unsigned int> Virtual_node_hash_vec;
if (0 = get_virtual_node_hash (node, Virtual_node_hash_vec)) return false;
for (size_t i = 0; i < virtual_node_hash_vec.size (); i++) {m_node_map[virtual_node_hash_vec[i]] = node;
return true; BOOL Consistent_hash::d el_node (const string& node) {vector<unsigned int> Virtual_nOde_hash_vec;
if (0 = get_virtual_node_hash (node, Virtual_node_hash_vec)) return false;
for (size_t i = 0; i < virtual_node_hash_vec.size (); i++) {m_node_map.erase (virtual_node_hash_vec[i));
return true;
} string Consistent_hash::get_node (const string& key) {if (M_node_map.empty ()) return "";
unsigned key_hash = M_hash_func (Key.c_str ());
map<unsigned int, String>::iterator it = M_node_map.lower_bound (Key_hash);
if (it = = M_node_map.end ()) {return m_node_map.begin ()->second;
Return it->second;
} size_t Consistent_hash::get_all_node (set<string>& nodes) {nodes.clear ();
for (map<unsigned int, string>::iterator it = M_node_map.begin ();
It!= m_node_map.end ();
++it) {Nodes.insert (It->second);
return Nodes.size ();
} size_t Consistent_hash::get_node_count () {set<string> nodes;
return Get_all_node (nodes);
}
#include <iostream>
#include "consistent_hash.h"
int main ()
{
Consistent_hash C;
Vector<string> A;
A.push_back ("192.10.59.1:80");
A.push_back ("192.10.59.2:80");
A.push_back ("192.10.59.3:80");
A.push_back ("192.10.59.4:80");
A.push_back ("192.10.59.5:80");
C.init (A, 1);
set<string> nodes;
Cout<<c.get_all_node (nodes) <<endl;
Cout<<c.del_node ("192.10.59.1:80") <<endl;
Cout<<c.get_all_node (nodes) <<endl;
Cout<<c.add_node ("192.10.59.1:80") <<endl;
Cout<<c.get_all_node (nodes) <<endl;
for (int i = 0; i < 10000000 i++)
{
char b[1024] = {0};
sprintf (b, "%d", I);
string t = B;
cout<< "node=" <<c.get_node (t) <<endl;
}
}