一:一致性hash算法 一致性hash场景描述: 假如有三台缓存服务器,此时一个数据要缓存到其中一台,并且要一次查询快速定位。一种简单实用的方法就是 对此时数据标识(key)进行hash取值,然后根据hash值与服务器数量取余获得余数,此数代表了那一台服务器, 此时数据就缓存在这台服务器上。但是会有个问题,当缓存服务器数量增加或者减少时,原先缓存的数据因为 服务器数量的增加或者减少,导致余数变化,此时获取缓存肯定是失效的,而且是全局缓存失效,这时导致缓存 失去意义,这种情况下,出现了一致性hash 概念: 上述普通算法是根据服务器数量进行取模运算,而一致性hash就是对 2^32 取模 把 2^32 想象成一个圆,也就是一个圆上分布了 2^32 个点,又被称为 hash环 上述hash值对 2^32 取模后(假设为A),会落在 0-2^32-1 上的某一个点,而此时用 服务器ip % 2^32 取模之后的数, 代表此时服务器所在的点(假设为B),假设 A等于B 或者 A在B的逆时针方向,且靠的最近(hash环是按照顺时针方向 定义,也就是A会找最近并且在它的顺时针方向上的点,即大的点) 出现服务器数量增加或者减少后,hash值对于 2^32 取模后的值是相对不变的,也就是缓存的点总是不变,变化的只是 hash环上某一节点上服务器数的增减,但是影响只限于增减那一段上的,其他地方不会影响。这就是一致性hash相对于普通 hash的优点 优点:只影响增减那一段上的数据,其它节点上无感知,正常运行。而普通的取模算法就会导致所有的节点数据异常,一个影响 部分,一个影响全部 hash环的偏斜: 对于服务器ip进行hash取模,很大可能各个节点不是均匀散落在hash环上,这就是hash环的偏斜,由此会导致某一服务器 上会分布大量数据,而为了防止这种现象,使用“虚拟节点”解决此问题 虚拟节点: 虚拟节点是真实节点在hash环上的复制品,一个真实节点可以对应许多的虚拟节点,当然虚拟节点越多,分布就会越均匀, 数据分布效果越好。 分析:比如有一百个虚拟节点,从1-100,hash值+ 1-100 ,然后取模,此时大的数取值会大,小的数取值会小,效果也不好 此时 hash算法要定义一个尽量差异大的,这样相近的hash也会分散开,使得多个节点及其虚拟节点相互混杂,这样 效果越好,使用虚拟节点就解决了hash环偏斜的问题 二:代码实现及其使用测试 代码实现:Ketama.java 使用: /* * 一致性hash实现:将所有的在线服务都存储到统一 treeMap中,进行负载均衡(路由到其他地址) */ List servers = new ArrayList<>(); for (String server : servers){ Logs.info("server router add ketama server({})", server); ketama.add(server); } 测试:Ketama.java中 main() 方法,详细介绍如何使用 ###资料链接 hash一致性 经典理解:http://www.zsythink.net/archives/1182/