采用一致性hash算法可以将资源分散保存在多台缓存服务器上,减少访问源站点服务器的次数,缓解源站点服务器的压力。
原理:根据相同的key值计算哈希值映射到哈希环上的位置相同,资源
hash环空间:当采用一般的哈希函数:M = hash(key) mod N存放资源时,若新增/删除服务器,会造成大量的数据迁移,导致网络通信压力的剧增,甚至导致数据库宕机(N值变化,M值也会跟着变化,此时大部分缓存失效,大量请求回源站点);若采用哈希环,则只对其中部分数据造成影响。
哈希环是一个虚拟的环状结构,通常表示为一个圆圈。在这个环上,每个节点被分配一个唯一的位置。服务器根据ip哈希到环上,创建hash环时为了防止hash环倾斜,会创建大量的虚拟节点,使得环中的服务器节点尽可能均匀。每个资源再根据设置的缓存key,顺时针转动存储到了环上。如果此时需要对服务器进行扩容或者缩容,也只会影响到该台及顺时针方向上最近的一台服务器上的混存,大部分缓存不受影响。
hash环倾斜:主要是节点数量较少时,可能会出现节点在哈希空间中分布不平衡的问题,可能导致大部分资源集中缓存在某几个真实节点中,可以通过创建虚拟节点来解决。
步骤如下:
a. 将服务器ip作为key值计算hash值映射到哈希环上:hash(key)mod 2^32
b. 创建一些虚拟节点(虚拟服务器,与真实服务器对应)
c. 寻址:将播放资源(通过缓存key值计算hash值)以同样的方式映射到哈希环上,寻址逻辑:顺时针寻找最近的一个节点,则资源保存在第一个找到的服务器上(如果是虚拟节点,则在对应的真实服务器上)
节点创建、初始化、寻址细节
a. 解析upstream块获取server list;
b. 各个server根据权重,乘以常量160,变成weight*160个点的数组points;
c. 根据server的 host,‘\0’, port 计算crc32-hash作为base_hash ,固定不变;
d. 遍历points,根据hash(i+1) = crc32(basehash, hash(i))设置point[i+1] = hash(i+1),填满数组;
e. 循环server 列表,填满points[server1_weight x 160 + server2_weight x 160 + .......];
f. 对points[]数组按value值 crc32-hash 做快排,然后去重放入新points[]数组
g. 对请求的key做crc32-hash得到req-hash,在pionts[]数组中,按二分查找数组中等于req-hash的对象points[crc32(request)]
h. 从points[crc32(request)]开始遍历查找points[]数组中可提供服务的server,排除down的,直到找到可提供服务的target-server.若有多个可提供服务的server,则使用轮询选择一个server。