先来一张图,memcached分布式集群的访问模型图:
上图中,api访先问memchached集群时,先通过路由算法获取key所对应的物理机器IP,然后再到相应的服务器上获取缓存数据。
下面通过路由算法来解释hash一致性算法:
传统hsah算法
最简单的计算方法是对key的hash取模,然后获取所在机器。如下图所示,假如有3台机器作为集群,当要访问一个key的value时,先对key取hash值然后除以3,即可得出在第几台机器。然后去相应的机器访问取值。
上述算法是最简单最直接的的办法。但是会有很大的缺陷。
如下图,当业务访问量增加,需要在集群中增加一台缓存服务器解决所面临的的访问压力。由于这台机器的加入,需要修改原来的路由算法,改成hash值取4。这样经过计算后的hash值最终才会落到4台机器上。
但是,经过计算,这样做会导致原来 75%的数据命不中缓存。如果原来有100台服务器,在加入一台后,将会导致99%的缓存无法命中。而此时,大量的访问最终会压到数据库,从而导致数据库宕机。显然是得不偿失的。
另一种极端情况是,当有一台服务器突然失效的时候,同样会造成大量的缓存无法命中。
其中有一种解决办法:半夜的时候加入(网站的访问低谷通常在半夜),然后通过模拟请求,慢慢给缓存预热。
一致性hash算法
上面的算法显然会使系统的扩展能力差、容错能力不佳。下面介绍的一致性hash算法将解决单台服务器对集群系统造成过大的影响。
1、首先构造一个hash环,如上图左。范围一般去0~2^32整数。
2、根据节点的名称,将缓存服务器放置在这个hash环上。如上图的node1,node2代表两个节点的机器。
3、查找时,先算出这个key的hash值,然后在环上顺时针找到最近的一个节点机器即可。
如果需要增加一个机器时,在环上插入该机器,如下图:
加入node3机器后,不需要修改路由算法,会有部分key值落入node3机器中。node1不受影响,node2会有部分缓存落入新的节点,从而减轻压力。如果由3台缓存服务器扩展的4台,则命中原来缓存的概率是75%。而当100台扩展到101台时,将会有99%的缓存命中原来的机器。这样就避免了原来命不中缓存的问题。
实际应用中,会通过二叉树来查找最近的节点。这里就不拓展了。
但是依然存在缺点,那就是插入一个节点后,只能影响下一个节点的机器。即插入node3节点,只能减缓node2上面的压力。这显然不是我们需要的。
虚拟节点+hash一致算法
如上图中,假设只有两台机器node1,node2。其中node1在环上的虚拟节点是V11,V12, node2在环上的虚拟节点是V21, V22。也就是说,当在key的hash值在环上找到最近的点V11或者V12,则需要访问node1节点的机器,否则就是另一台机器。
当需要扩容时,插入node3机器,此时在环上插入虚拟节点V31,V32。当数据落入这两个节点时,需要访问的是node3物理机器。显然从上图中看出,每个物理机器对应的虚拟节点越多,则负载越均衡。
那么在实践中,一台机器对应多少个虚拟服务节点合适呢?如果太多了,则会影响性能;太少了又会导致负载均衡不起来。
一般来说,经验值是150.
当然还需要根据集群规模和要求的精度具体对待。
今天的分享就到这里咯,能帮助到你,希望能点个赞哟~~