1. 解决的问题
在分布式服务中,往往有这样的场景:将某个用户或某台机器的请求负载路由到固定的某台服务器上。简单的做法直接是使用哈希算法,h = hash(key) % N ,该算法的核心思想是:将服务器编号,使用哈希算法取根据某类请求参数key(用户id或IP)计算出一个哈希值,再对该哈希值用服务器数据N进行取余(%)操作,从而得到服务器编号。使用该算法有一个问题,就是服务器数据数目(N)增加中或减少的时候,h的值都会被改变,即请求会负载到新的服务器上,有可能会导致状态数据的失效。有没有一种算法,既可以将同一请求负载到同一台服务器上,又可以在服务器增加或减少的时候将请求的变更控制在一定的范围内,所以提出了一致性哈希算法。
一致性哈希算法(Consistent Hashing)最早在论文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中被提出,其原理如下:
一致性哈希算法将整个哈希值(整数)空间组织成一个0~2^32-1的虚拟哈希环,首先,服务器按照名称(或编号)取哈希,并将该哈希值放置在哈希环上,然后再对key取哈希,按照随时针方向查找离该值最近的服务器结点哈希值,从而完成key与服务器的匹配映射工作。
通过一致性哈希算法,服务器的增加或减少只会影响该服务器周围的请求,不会扩大到整个哈希环,从而保证算法的可扩展性。
一致性哈希算法也有一个问题,就是服务器较少时,可能出现服务器之间负载的请求可能不均衡,有些服务器负载的请求可能过多,而有些服务负载较少。解决这个问题的关键是增加哈希环上服务节点的数量,在物理服务器不能增加的情况下,可以将一个服务结点映射为多个虚拟结点,均匀分布在哈希环上,从而解决该问题。