介绍和C库源代码,用于一致的哈希。
libconhash是一个一致的散列库,可以在Windows和Linux平台上编译,具有以下功能:
现在我们将考虑通常的负载均衡方式。选择缓存对象o的机器编号为:
hash(o) mod n
这里,n是缓存机的总数。这样做很好,直到你添加或删除缓存机器:
hash(o) mod (n+1)
2.当您删除缓存机器时,对象
o
将被缓存到机器中:
hash(o) mod (n-1)
所以你可以看到几乎所有的对象都会被嵌入一个新的位置。这将是灾难,因为始发内容服务器被来自缓存机器的请求所淹没。这就是为什么你需要一致的哈希。
一致的散列可以保证当缓存机器被移除时,只有缓存在其中的对象将被重新刷新; 当添加新的高速缓存机器时,只有相当少的对象将被重新刷新。
现在我们将逐步进行一致的散列。
通常,散列函数将映射值成一个32位的密钥,0~2^32-1
。现在想象将范围映射到一个圆圈,然后键将被包裹,0将后跟2 ^ 32 -1,如图1所示。
图1
现在考虑四个对象:object1~object4
。我们使用哈希函数来获取它们的键值并将其映射到圆中,如图2所示。
图2
hash(object1) = key1;
.....
hash(object4) = key4;
一致散列的基本思想是使用相同的散列函数将缓存和对象映射到同一散列空间。
现在考虑我们有三个缓存A,B和C,然后映射结果将如图3所示。
hash(cache A) = key A;
....
hash(cache C) = key C;
图3
现在所有的缓存和对象都被放入同一个空间,所以我们可以确定如何将对象映射到高速缓存中。以对象obj
为例,从哪里开始,obj
顺时针旋转,直到找到服务器。如果该服务器关闭,则转到下一个服务器,等等。见上图3。
根据该方法,object1
将缓存到缓存A中; object2
并将object3
缓存到缓存C中,并将object4
缓存到缓存B中。
现在考虑这两种情况,一个缓存是down和remove; 并添加一个新的缓存。
如果缓存B被删除,那么只有在B中缓存的对象将被重新刷新并移动到C; 在示例中,参见object4
图4所示。
图4
如果添加了一个新的高速缓存D,并且D 在环中object2
和之间object3
进行了哈希,那么只有在D和B之间的对象才会被重新刷新; 在示例中,参见object2
图5所示。
如果您没有部署足够的缓存,可能会在缓存之间分配非常不均匀的对象。解决方案是介绍“虚拟节点”的思想。
虚拟节点是圆中缓存点的副本,每个实际高速缓存对应于圆中的几个虚拟节点; 每当我们添加一个缓存时,实际上我们为它创建了一些虚拟节点,并且当缓存被移除时,我们从圆圈中删除所有的虚拟节点。
考虑上面的例子。系统中有两个高速缓存A和C,现在我们引入了虚拟节点,副本是2,那么三个将是4个虚拟节点。缓存A1和缓存A2代表高速缓存A; 高速缓存C1和高速缓存C2表示高速缓存C,如图6所示。
图6
然后,从对象到虚拟节点的映射将是:
objec1->cache A2; objec2->cache A1; objec3->cache C1; objec4->cache C2
当您获得虚拟节点时,您将获得缓存,如上图所示。
所以object1和object2被缓存到缓存A中,对象3和对象4被缓存到高速缓存中。结果现在更加平衡。
所以现在你知道什么是一致的散列。
/* initialize conhash library
* @pfhash : hash function, NULL to use default MD5 method
* return a conhash_s instance
*/
CONHASH_API struct conhash_s* conhash_init(conhash_cb_hashfunc pfhash);
/* finalize lib */
CONHASH_API void conhash_fini(struct conhash_s *conhash);
/* set node */
CONHASH_API void conhash_set_node(struct node_s *node,
const char *iden, u_int replica);
/*
* add a new node
* @node: the node to add
*/
CONHASH_API int conhash_add_node(struct conhash_s *conhash,
struct node_s *node);
/* remove a node */
CONHASH_API int conhash_del_node(struct conhash_s *conhash,
struct node_s *node);
...
/*
* lookup a server which object belongs to
* @object: the input string which indicates an object
* return the server_s structure, do not modify the value,
* or it will cause a disaster
*/
CONHASH_API const struct node_s*
conhash_lookup(const struct conhash_s *conhash,
const char *object);
Libconhash非常容易使用。项目中有一个示例显示如何使用库。
首先,创建一个conhash实例。然后可以添加或删除实例的节点,并查找对象。
更新节点的副本功能尚未实现。
/* init conhash instance */
struct conhash_s *conhash = conhash_init(NULL);
if(conhash)
{
/* set nodes */
conhash_set_node(&g_nodes[0], "titanic", 32);
/* ... */
/* add nodes */
conhash_add_node(conhash, &g_nodes[0]);
/* ... */
printf("virtual nodes number %d\n", conhash_get_vnodes_num(conhash));
printf("the hashing results--------------------------------------:\n");
/* lookup object */
node = conhash_lookup(conhash, "James.km");
if(node) printf("[%16s] is in node: [%16s]\n", str, node->iden);
}
转自:
https://www.codeproject.com/Articles/56138/Consistent-hashing