0%

分布式系统之负载均衡

负载均衡 (load balance)

「负载均衡」是指,通过一定的算法使请求可以均匀的宠幸服务提供方,做到雨露均沾。市面上,软件硬件产品一大把,解决的最最核心的问题都是选谁

按实现方式,可以分为硬件负载均衡(如 F5 、A10)、软件负载均衡(如 LVS、Nginx、HAProxy)、DNS 负载均衡。硬件负载均衡和 DNS 负载均衡我们不过多关注,重点看一下软件负载均衡。

软件负载均衡又分四层和七层负载均衡,四层负载均衡就是在网络层利用 IP 地址端口进行请求的转发,基本上就是起个转发分配作用。而七层负载均衡就是可以根据访问用户的 HTTP 请求头、URL 信息将请求转发到特定的主机。LVS 为四层负载均衡。Nginx、HAProxy 可四可七。

除了专用硬件和 Nginx 这种专业软件提供负载均衡外,在代码中直接实现也是种常见的方式。比如 Spring Cloud 体系中的 Ribbon 组件提供了轮询、随机、根据响应时间加权几种负载策略,比如使用 Memcached 集群时通常会在 client 中采用 hash 取模或者一致性哈希来使数据均匀分布。

常见算法

常见的有:随机,轮询,最小链接数,一致性哈希

随机(Random)

根据后端服务器列表的大小值来随机选择其中一台进行访问,代码如下:

优点:实现简单,通过系统随机函数随机选择其中一台进行访问

缺点:不适用后端机器承载能力不一致的情况

权重随机(Weighted Random)

各个节点带有不同的权重,虽然随机选择但是期望不同权重的节点被选择的几率不一样, 权重高的被选中的几率大,权重低的被选中的几率小。

优点:实现简单,采用权重改变了被选中的概率;

缺点:不适用后端机器承载能力不一致的情况。

轮询(Round Robin)

把所有待选择的机器看做是一个个的点,所有点串起来一个圆。想象一下,轮询就是对圆上的每一个点,顺时针遍历,在每个节点上停留一下。我们通过请求的次数 pos ,来实现顺时针选择。需要修改 pos 的线程,只有获取到锁才能对该值做修改,当该值大于等于服务器列表长度时,重新从 0 开始遍历,达到循环一周的目的。

优点:相对来说请求可以做到绝对平衡;

缺点:为了绝对平衡,需要保证 pos 修改时的互斥性,引入了同步锁会带来性能下降。

权重轮训(Weighted Round Robin)

不同的后端服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不相同。给配置高、负载低的机器配置更高的权重,让其处理更多的请;而配置低、负载高的机器,给其分配较低的权重,降低其系统负载,加权轮询能很好地处理这一问题,并将请求顺序且按照权重分配到后端。

最小连接数(Least Connections)

从已有的后端列表中,选择正在处理的连接数 / 请求数最少的节点出来提供服务。既然要判断连接数 / 请求数,那么每个节点都需要保存一个正在处理的连接数 / 请求数的信息,然后选取节点的时候判断一下, 选择连接数最少的那个节点。

首先找到服务提供者当前最小的活跃连接数,如果一个服务提供者的服务连接数比其他的都要小,则选择这个活跃连接数最小的服务提供者发起调用,如果存在多个服务提供者的活跃连接数,并且是最小的,则在这些服务提供者之间选择加权随机算法选择一个服务提供者。

优点:根据服务器当前的请求处理情况,动态分配;

缺点:算法实现相对复杂,需要监控服务器请求连接数。

一致性哈希(Consistent Hash)

根据后端节点的某个固定属性计算 hash 值,然后把所有节点计算出来的 hash 值组成一个 hash 环。请求过来的时候根据请求的特征计算该特征的 hash 值(使用跟计算后端节点 hash 值相同的 hash 函数进行计算), 然后顺时针查找 hash 环上的 hash 值,第一个比请求特征的 hash 值大的 hash 值所对应的节点即为被选中的节点。

某一部分节点发生故障时,或者新的节点动态的增加进来时都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

虚拟哈希节点

上面的 hash 环有一个问题,就是节点的 hash 值不一定是均匀的分布在 hash 环上的,这样就会导致部分节点上承受太多的请求。解决办法是引入虚拟节点:每个节点重复 n 次,把这些虚拟节点的 hash 值(跟实际节点的 hash 值不一样,也就是说需要在节点属性中加点东西保证每个虚拟节点跟实际节点的 hash 值不一样,互相之间也要不一样)也加入到 hash 环中以此来保证分布更均匀。

优点:具有较好的容错性和可扩展性,节点加入或者去除,只有少量数据需要迁移;

缺点:没有解决热点问题,会出现部分节点需要处理大量请求。

IP地址散列

通过管理发送方IP和目的地IP地址的散列,将来自同一发送方的分组(或发送至同一目的地的分组)统一转发到相同服务器的算法。当客户端有一系列业务需要处理而必须和一个服务器反复通信时,该算法能够以流(会话)为单位,保证来自相同客户端的通信能够一直在同一服务器中进行处理。

优点:xxx

缺点:xxx

URL散列

过管理客户端请求URL信息的散列,将发送至相同URL的请求转发至同一服务器的算法。\

Nginx 使用的负载均衡算法

轮询

默认就是

加权轮询

1
2
3
4
upstream linuxidc{       
server 10.0.0.77 weight=5;
server 10.0.0.88 weight=10;
}

ip_hash

1
2
3
4
5
upstream favresin{      
ip_hash;
server 10.0.0.10:8080;
server 10.0.0.11:8080;
}

fair(第三方)

1
2
3
4
5
6
# 按照后端服务器的响应时间来分配请求,响应时间短的优先分配。 
upstream favresin{
server 10.0.0.10:8080;
server 10.0.0.11:8080;
fair;
}

url_hash(第三方)

1
2
3
4
5
6
7
# 按照访问url的hash结果来分配请求,每个固定的url访问同一个后端服务器。如果后端服务器是缓存时效率高。 
upstream resinserver{
server 10.0.0.10:7777;
server 10.0.0.11:8888;
hash $request_uri;
hash_method crc32;
}

参考

微信文章

掘金文章