Basic Scene
For example, you have n cache server (behind the cache), then how to map an object to the n cache, you are likely to use similar to the following common method to compute the hash value of object, and then evenly mapped to n cache;
Remainder algorithm: Hash (object)%N
Everything is working properly, and then consider the following two cases;
11 Cache server M down (in practical applications must consider this situation), so that all mapped to cache M object will be invalidated, how to do, need to remove the cache m from the cache, this time cache is N-1, mapping formula into ha Sh (object)% (N-1);
2 because the access is heavier, need to add cache, this time cache is n+1, mapping formula into a hash (object)% (n+1);
1 and 2 mean something. This means that all of a sudden, almost all of the cache has failed. For the server, this is a disaster, flood-like access will directly flush back to the server;
To consider the third problem, because the hardware is more and more strong, you may want to add more nodes to do a bit more work, obviously the hash algorithm above can not do.
Is there any way to change this situation, this is consistent hashing ... hash algorithm and monotonicity
One metric of the Hash algorithm is monotonicity (monotonicity), defined as follows:
Monotonicity is the addition of new buffers to the system if some content has been allocated to the corresponding buffer by hashing. The result of the hash should be that the original allocated content can be mapped to the new buffer without being mapped to other buffers in the old buffer set.
It is easy to see that the above simple algorithm hash (object)%N difficult to meet the monotonic requirements. the principle of consistent hashing consistent hash
Consistent hashing is a hash algorithm, simply, in removing/adding a cache, it can be as small as possible to change the existing key mapping relationship, as far as possible to meet the requirements of monotonicity. 1. Annular Hash Space
Consider the usual hash algorithm is to map value to a 32 of the key value, that is, the 0~2^32-1 of the second square of the numerical space; we can think of this space as a circle of the first (0) tail (2^32-1), as shown in Figure 1 below.
Circle Space 2. Map the contents (objects) that need to be cached to the hash spaces
Next, consider 4 object Object1~object4, the distribution of the hash value key on the ring by the hash function is shown in Figure 2.
Hash (object1) = Key1;
... ...
Hash (OBJECT4) = Key4;
Object 3. Map Server (node) to hash space
The basic idea of consistent hashing is to map both the object and cache to the same hash value space and use the same hash algorithm.
Assuming that there are currently 3 servers (nodes) for a,b and C, the mapping results will be shown in Figure 3 and they are arranged in the hash space with the corresponding hash value.
The general method can use the IP address of the Server (node) machine or the machine name as the hash input.
Hash (cache A) = key A;
... ...
Hash (cache C) = key C;
Cache 4. Map objects to cache
Now the cache and objects have been mapped to the hash value space through the same hash algorithm, and the next thing to consider is how to map the object to the cache.
In this annular space, if you proceed clockwise from the object's key value until you meet a cache, the object is stored on the cache because the hash value of the object and cache is fixed, so this cache must be unique and certain. So do not find the object and cache mapping method?
Continue with the above example, the object Object1 will be stored on cache A, according to the above method, Object2 and object3 correspond to cache C; Object4 to cache B; 5. Review cache Changes
Previously said, through the hash and then the residual method to bring the biggest problem is not to meet the monotony, when the cache changes, cache will be invalidated, and then to the background server caused a huge impact, now to analyze and analyze the consistent hashing algorithm.
5.1 removing cache
Consider the assumption that cache B hangs, depending on the mapping method described above, only those objects that traverse the cache B counterclockwise until the next cache (cache C), or those that would otherwise be mapped to cache B.
So here you only need to change the object Object4, remap it to cache C; see Figure 4.
Fig. 4 Cache Map After cache B is removed
5.2 Add Cache
Consider adding a new cache D, assuming that in this annular hash space, cache D is mapped between the object Object2 and Object3. The affected will only be those objects that traverse the cache D counterclockwise until the next cache (cache B) (they are also mapped to part of the object on cache C) and remap the objects onto cache d.
So here you just need to change the object object2 and remap it to cache D; see Figure 5.
Figure 5 Mapping relationship after adding cache D 6. Virtual Node
Another metric for hashing algorithms is balance (Balance), defined as follows:
of balance
Balance means that the result of a hash can be distributed to all buffers as much as possible, so that all buffer space is exploited.
The hash algorithm is not guaranteed absolute balance, if the cache is less, the object can not be evenly mapped to the cache, for example, in the above example, only the deployment of cache A and cache C, in 4 objects, cache a only store object1, While cache C stores Object2, Object3 and Object4, the distribution is very uneven.
To address this situation, consistent hashing introduces the concept of "virtual node", which can be defined as follows:
Virtual node is the actual node in the hash space of the replica (replica), an actual node corresponding to a number of "virtual nodes", the corresponding number also become "copy number", "Virtual node" in the hash space in the hash value arrangement.
Still, for example, to deploy cache A and cache C only, we have seen in Figure 4 that the cache distribution is uneven. Now we introduce the virtual node, and set the "number of copies" for 2, which means that there will be 4 "virtual nodes", Cache A1, cache A2 represents cache A; Cache C1, Cache C2 represents cache C; Suppose a more desirable situation , see Figure 6.
Figure 6 Mapping relationship after the introduction of "Virtual Node"
At this point, the mapping between the object and the virtual node is:
Objec1->cache A2; objec2->cache A1; Objec3->cache C1; Objec4->cache C2;
So the objects Object1 and Object2 are mapped to cache a, and object3 and Object4 are mapped to cache C; The balance has been greatly improved.
After the virtual node is introduced, the mapping relationship is converted from the {Object-> node} to the {Object-> virtual node}. The mapping relationship between the cache of the object being queried is shown in Figure 7.
Figure 7 Query Object location cache
The hash calculation of "virtual node" can be based on the IP address of the corresponding node plus the digital suffix. For example, suppose cache A has an IP address of 202.168.14.241.
Before introducing the "virtual node", compute the hash value of cache A:
Hash ("202.168.14.241");
After introducing the virtual node, compute the hash value of the "virtual section" point cache A1 and cache A2:
Hash ("202.168.14.241#1"); Cache A1
Hash ("202.168.14.241#2"); Cache A2 following code implementation demo
#!/usr/bin/env python #-*-coding:utf-8-*-from zlib import CRC32 import Memcache class Hashconsistency (object):
def __init__ (self, Nodes=none, replicas=5): # Virtual node corresponds to real node self.nodes_map = [] # Dictionary mapping of real node and virtual node Self.nodes_replicas = {} # real node self.nodes = nodes # Number of virtual nodes created per real node Self.replicas
= Replicas if self.nodes:for node in Self.nodes:self._add_nodes_map (node)
Self._sort_nodes () def get_node (self, Key): "" "according to the hash value of the key value, return the corresponding node algorithm is: To return the first node larger than Key_hash
"" "Key_hash = ABS (CRC32 (key)) #print ' (%s '% key_hash for node in Self.nodes_map: If Key_hash > Node[0]: Continue return node return None def add_node (self, nod
e): # Add Nodes self._add_nodes_map (node) self._sort_nodes () def remove_node (Self, node): # Delete Nodes if node nOT in Self.nodes_replicas.keys (): Pass discard_rep_nodes = Self.nodes_replicas[node] Self.node S_map = filter (lambda x:x[0] not in Discard_rep_nodes, Self.nodes_map) def _add_nodes_map (Self, node): # Increase Virtual
Pseudo node to Nodes_map list nodes_reps = [] for i in Xrange (self.replicas): Rep_node = '%s_%d '% (node, i) Node_hash = ABS (CRC32 (Rep_node)) self.nodes_map.append (Node_hash, node) nodes_reps.
Append (node_hash) # Real node and virtual node dictionary mapping Self.nodes_replicas[node] = Nodes_reps def _sort_nodes (self): # order Virtual Nodes Self.nodes_map = sorted (Self.nodes_map, Key=lambda x:x[0]) memcache_servers = [' 127.0.0.1:7 001 ', ' 127.0.0.1:7002 ', ' 127.0.0.1:7003 ', ' 127.0.0.1:7004 ',] h = hashconsistency (memcache_servers) for K in H.nodes_map:print k mc_servers_dict = {} for MS in MEMCACHE_SERVERS:MC = memcache.
Client ([Ms], debug=0) mc_servers_dict[ms] = MC
# 10 this to memcache add key, where the consistency hash is used, then key will be based on the hash value to the corresponding virtual node for I in Xrange (a): key = ' key_%s '% i print key Server = H.get_node (key) [1] mc = Mc_servers_dict[server] Mc.set (key, i) print ' server:%s '% Server pri NT MC