1.1 Hash算法应用场景

Hash算法在分布式集群架构中的应用场景

Hash算法在很多分布式集群产品都有应用,比如分布式集群Redis、Hadoop、ElasticEearch,MySql分库分表,Nginx负载均衡等。

主要的应用场景两个:

  • 请求的负载均衡(nginx的ip_hash策略)

    Nginx的IP_Hash策略可以在客户端ip不变的情况下,将其发出的请求始终路由到同一个目标服务器上,实现会话粘滞,避免session共享问题

    假设: 没有IP_Hash策略,该如何实现会话粘滞?

    可以维护一张映射表,存储客户端IP或者sessionId与具体目标服务器的映射关系,tomcat1>

    缺点:

    1)在客户端很多情况下,映射表庞大,浪费内存空间

    2)客户端上下线,目标服务器上下线,都会导致需要重新维护映射表,映射表维护成本大

    如果使用哈希算法,事情将会变得简单很多,可以对ip地址或者sessionId进行哈希值的计算,哈希值与服务器数量进行取模运算,得到的值就是当前应该被路由到服务器编号,如此,同一个客户端ip发送过来的请求就可以路由到同一个目标服务器,实现会话粘滞。

  • 分布式存储

    以分布式内存中间件Redis为例,集群中有redis1、redis2、redis3三个Redis服务器。

    那么进行书库出差时,,value1>

1.2 普通Hash算法存在的问题

普通Hash算法存在一个问题,以IP_Hash为例,假定下载用户ip固定没有发生变化,现在tomcat3出现问题,down机了,服务器数量由3个变为了2个,之前所有的求模都需要重新计算。

普通Hash算法存在的问题示意图:

如果在真实生产环境下,后台服务器很多台,客户端也很多,那么影响范围将会很大(产线事故),缩容/扩容都会存在这样的问题,大量用户的请求会被路由到其他的目标服务器处理,用户在原来的服务器中的会话都会丢失。

1.3 一致性Hash算法

一致性哈希算法思路示意图:

先有一条直线,直线开头和结尾分别定为1和2的32次方减1,这相当于一个地址,对于这样一条线,折换成一个圆环形成闭环,这样的闭环成为hash环。把服务器的ip或者主机名求hash值然后对应到hash环上,针对客户端用户,也根据它的ip进行hash求值,对应到环上某个位置。

问题1:如何确定一个客户端路由到那个服务器处理呢?

按顺时针方向找最近的服务器节点

假如将服务器3下线,服务器3下线后,原来路由到3的客户端重新路由到服务器4,对于其他客户端没有影响只是这一小部门受到影响(请求的迁移达到最小,这样的算法对分布式集群场景非常合适,避免了大量请求迁移)

一致性哈希算法(缩容-减少服务器)示意图:

增加服务器5之后,原来路由到3的部分客户端路由到新增服务器5上,对于其他客户没有影响只是这一小部分受到影响(请求的迁移达到最小,这样的算法对分布式集群场景非常合适,避免了大量请求迁移)

一致性哈希算法(扩容-增加服务器)示意图:

1)上述,每一台服务器负责一段哈希环,一致性哈希算法对于阶段的增加都只需重定位环空间的一小部分数据,具体较好的容错性和可扩展性。

但是, 一致性哈希算法在服务节点太少时,容器因为节点分布不均匀而造成数据倾斜问题。例如系统中有两台服务器,其环分布如下,节点2只能负责非常小的一段,大量的客户端请求落节点1,这就是数据(请求)倾斜问题。

2)解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。

具体做法在服务器ip或者主机名的后面增加编号来实现。比如,可以为每台服务器计算三个虚拟节点,于是可以分别计算“节点1的ip#1”、“节点1#2”、“节点1#3”;“节点2的ip#1”、“节点2#2”、“节点2#3”的哈希值,于是形成六个虚拟节点,当客户端被路由到虚拟节点的时候其实是被路由到该虚拟节点所对应的真实节点

一致性hash算法+虚拟节点方案示意图: