大规模分布式系统架构与设计实战笔记6
在《大规模分布式系统架构与设计实战笔记》的第四章,提到了分布式缓存的负载均衡问题。
对于分布时的负载均衡问题,很多人会想到一致性算法,一致性算法提出了一个环的思想,用集群中的多个节点将环分成了好多段,每一段对应着一些key的取值(顺时针),当计算出需要存储的数据的key值后,按照顺时针方向存储到离他的key值最近的服务器节点上去。
在这个算法中,我们可以看到:假设现在环上有ABCD四个节点,AB,BC,CD,DA之间的key的取值分别为0~9,10~19,20~29,30~39.
当某个服务器发生故障的时候,比如A故障,那么新的需要映射到A的数据就会映射到B,而原来在A中的数据就取不到了,因此为了提高一致性哈希算法的容错能力,为换上的每个节点增加备用节点,当主节点死掉后,备用节点跟上。这样在一致性哈希算法中节点死掉而产生影响的情况就被我们解决了。
当节点增加时,比如AB之间增加了一个节点E,那么原来映射到B的一部分节点就会映射到E,当然,对于新增加的节点查看他是没有问题的,但是对于那些原来映射到A后来映射到E的数据,查找他时,根据key值首先找到的是E,发现E没有要找的数据,接下来顺时针找到B,在B上找到目标数据,接下来将该数据从B节点搬到A节点上,以后就可以很方便的查找了。
可以看到,这样一来,一致性hash算法解决负载均衡问题已经接近很完美了:同个使用master-slave结构来解决节点死掉产生的影响,而节点增加的情况有没有致命性的(发生错误)影响。
因此使用一致性hash算法的时候,我们只需要将key值计算的平均一点,使换上的各个节点均匀分布。
但是一致性hash算法还是会出现扩容后分布不均的情况,除非成倍的扩容,因此fourinone框架提供了一种基于日期key取模的解决方案。我们来看一下:
此方案在构建集群节点时会让节点自己记录他们加入集群的时间,比如现在集群中有4台节点,分别得时间是2010-01-01,2010-02-01,2011-01-01,2011-02-01,而我们的数据会生成一个含有时间信息的key值,比如2011-01-18的一个key值,那么该key值在时间上覆盖了前三个节点,因此他对3取模算出应该存储于哪个节点上。同样的,在该方案中,通过增加备用节点避免宕机的影响。至于扩容的影响,你会发现,无论如何的扩容,都不会对已经存储的数据有一丁点的影响,因为节点和key中都包含了时间的信息。
而我们仅仅需要解决的就是如何在扩容后让新增数据更多的存储在新的节点当中,这里,我们使用基于时间分组的方式,比如,现在对原来的4台节点的集群扩容,新增节点的时间为2012-01-01,2012-02-01,这样,集群中就有了6个节点,我们可以分成两组,2010组和2011组,然后在数据存储时,先根据key中的时间信息确定所在的组别然后在使用上面提到的方法。自此,fourinone的缓存负载均衡的问题解决完毕:
首先将集群中的服务器按照时间分组,然后fourinone在为数据生成key值时会加入时间的信息,这样根据key中的时间信息就可以确定数据要存储的节点的组别和具体的节点了。你会发现无论新增加的节点还是原来已经存储的节点都可以根据key很好的存储并且找到,因为他们用时间做了标记。