hash
hash即求散列值,可以将不确定长度的数据映射成一串固定值,节省空间且便于比较,通常用在辅助查找,去重等场景。
hash的目的可以用较少的数据空间来体现原有数据的差异性,即同一条数据hash后的值结果肯定是相等的,不等数据的hash后值会尽量分开,这样的特性便于寻址定位,比如一个数组,我们可以根据hash值对数组长度取模,根据取模位置直接设置和获取数据。当然由于不同数据的hash值可能相等,我们必须考虑如何解决hash冲突。hashmap,hashset即hash的一个典型应用。
一致性hash
对于分布式业务,如分布式缓存业务,在机器不变的情况下,存储和获取经过相同的hash算法并对机器数取模是会落在同一台机器的,但机器数量发生变化后,这样很可能导致缓存全部失效。一致性hash即为解决这个问题,在机器增减后,缓存失效的影响最小化。
一致性hash原理及实现
一致性hash采用一个hash环,并顺时针找对应机器节点的策略。
在Java中,hashCode为一个整数,我们将0和最大整数首尾相连,这样就形成了一个hash环,对缓存机器的ip地址进行hash可以得到一个整数。这个整数对应环上的一个节点,当缓存key过来,我们经过相同的hash算法就可以得到一个整数,它也对应环上的一个点。我们根据这个点在环上顺时针找位于它下方的机器节点,找到的第一个即它对应的缓存机器。
这样,在机器增加或减少中,由于采用顺序找的方式,缓存失效影响的范围将大大缩小,仅限当前节点前后对应的一片区域。
这种思路看起来很美好,但也有缺点,在机器少的情况下,如果两个机器节点的hash值较接近,在环上的位置也就会较接近,这样采用顺时针找的方式就会造成负载不均衡了,某一个节点可能就承担了大部分的数据读写任务。当然如果是之前的取模是没这个问题,余数一般是大致均匀分布。
解决负载不均衡的办法即增加虚拟节点,如可以对机器ip统一加标识,使参与hash排点的机器数量变多。如果有几百个,这样负载不均衡的概率将大大降低。
总结
一致性hash在分布式系统中有着广泛的应用,本质是解决分布式环境中节点增减后,对整体系统影响最小化的问题。解决思路为hash环顺时针查找,这样确保影响范围局限在一个区域,同时为解决机器数量少导致的负载均衡问题,又引入了虚拟节点,整体上是一个比较完善的分布式负载均衡解决方案。