Click here to Skip to main content
15,918,404 members
Articles / Programming Languages / C

Consistent hashing

Rate me:
Please Sign up or sign in to vote.
4.80/5 (31 votes)
2 Feb 2010BSD4 min read 223.6K   4.3K   51   6
An introduction to and a C library source code for consistent hashing.

What is libconhash

libconhash is a consistent hashing library which can be compiled both on Windows and Linux platforms, with the following features:

  1. High performance and easy to use, libconhash uses a red-black tree to manage all nodes to achieve high performance.
  2. By default, it uses the MD5 algorithm, but it also supports user-defined hash functions.
  3. Easy to scale according to the node's processing capacity.

Consistent hashing

Why you need consistent hashing

Now we will consider the common way to do load balance. The machine number chosen to cache object o will be:

hash(o) mod n

Here, n is the total number of cache machines. While this works well until you add or remove cache machines:

  1. When you add a cache machine, then object o will be cached into the machine:
  2. hash(o) mod (n+1)
  3. When you remove a cache machine, then object o will be cached into the machine:

    hash(o) mod (n-1)

So you can see that almost all objects will hashed into a new location. This will be a disaster since the originating content servers are swamped with requests from the cache machines. And this is why you need consistent hashing.

Consistent hashing can guarantee that when a cache machine is removed, only the objects cached in it will be rehashed; when a new cache machine is added, only a fairly few objects will be rehashed.

Now we will go into consistent hashing step by step.

Hash space

Commonly, a hash function will map a value into a 32-bit key, 0~2^<sup>32</sup>-1. Now imagine mapping the range into a circle, then the key will be wrapped, and 0 will be followed by 2^32-1, as illustrated in figure 1.

Image 1

Figure 1

Map object into hash space

Now consider four objects: object1~object4. We use a hash function to get their key values and map them into the circle, as illustrated in figure 2.

Image 2

Figure 2
hash(object1) = key1;
hash(object4) = key4;

Map the cache into hash space

The basic idea of consistent hashing is to map the cache and objects into the same hash space using the same hash function.

Now consider we have three caches, A, B and C, and then the mapping result will look like in figure 3.

hash(cache A) = key A;
hash(cache C) = key C;

Image 3

Figure 3

Map objects into cache

Now all the caches and objects are hashed into the same space, so we can determine how to map objects into caches. Take object obj for example, just start from where obj is and head clockwise on the ring until you find a server. If that server is down, you go to the next one, and so forth. See figure 3 above.

According to the method, object1 will be cached into cache A; object2 and object3 will be cached into cache C, and object4 will be cached into cache B.

Add or remove cache

Now consider the two scenarios, a cache is down and removed; and a new cache is added.

If cache B is removed, then only the objects that cached in B will be rehashed and moved to C; in the example, see object4 illustrated in figure 4.

Image 4

Figure 4

If a new cache D is added, and D is hashed between object2 and object3 in the ring, then only the objects that are between D and B will be rehashed; in the example, see object2, illustrated in figure 5.

Image 5

Figure 5

Virtual nodes

It is possible to have a very non-uniform distribution of objects between caches if you don't deploy enough caches. The solution is to introduce the idea of "virtual nodes".

Virtual nodes are replicas of cache points in the circle, each real cache corresponds to several virtual nodes in the circle; whenever we add a cache, actually, we create a number of virtual nodes in the circle for it; and when a cache is removed, we remove all its virtual nodes from the circle.

Consider the above example. There are two caches A and C in the system, and now we introduce virtual nodes, and the replica is 2, then three will be 4 virtual nodes. Cache A1 and cache A2 represent cache A; cache C1 and cache C2 represent cache C, illustrated as in figure 6.


Figure 6

Then, the map from object to the virtual node will be:

objec1->cache A2; objec2->cache A1; objec3->cache C1; objec4->cache C2

Image 7

When you get the virtual node, you get the cache, as in the above figure.

So object1 and object2 are cached into cache A, and object3 and object4 are cached into cache. The result is more balanced now.

So now you know what consistent hashing is.

Using the code

Interfaces of libconhash

/* 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 is very easy to use. There is a sample in the project that shows how to use the library.

First, create a conhash instance. And then you can add or remove nodes of the instance, and look up objects.

The update node's replica function is not implemented yet.

/* init conhash instance */
struct conhash_s *conhash = conhash_init(NULL);
    /* 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, "");
    if(node) printf("[%16s] is in node: [%16s]\n", str, node->iden);



This article, along with any associated source code and files, is licensed under The BSD License

Written By
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

QuestionA problem with vnode Pin
bestwolf198312-Nov-14 0:48
bestwolf198312-Nov-14 0:48 
GeneralMy vote of 4 Pin
Member 978423324-Jan-13 16:19
Member 978423324-Jan-13 16:19 
GeneralMy vote of 5 Pin
mjay8721-Aug-12 19:10
mjay8721-Aug-12 19:10 
General好东西。 Pin
happyhe10-Jun-10 0:50
happyhe10-Jun-10 0:50 
QuestionHow about just using virtual nodes Pin
supercat93-Feb-10 7:45
supercat93-Feb-10 7:45 
AnswerRe: How about just using virtual nodes Pin
sparkliang3-Feb-10 15:21
sparkliang3-Feb-10 15:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.