引言
负载均衡是分布式可靠性中非常关键的一个问题或技术,在一定程度上反映了分布式系统对业务处理的能力。比如,早期的电商抢购活动,当流量过大时,你可能就会发现有些地区可以购买,而有些地区因为服务崩溃而不能抢购。这,其实就是系统的负载均衡出现了问题。那么,究竟什么是负载均衡呢?接下来我们一起来看一看。
什么是负载均衡
先举个生活中常见的例子,我们在去超市购物结账的时候,会发现有几个收银窗口,平常的时候假设只有一个窗口和一个收银员。如果在平常人流量不大的情况上每个顾客需要等待时间很短,因为人流量小。但一旦到周六末的时候,人流量增大,每个人等待的时间就相应的变长了。长久以往,顾客们肯定不愿意去了,怎么办呢?我们新开几个窗口,多招几个收银员就好了。当然,我们也需要去督促顾客们去“均匀”排队,这样每个收银员都有一样的顾客,才能最大程度的最大减少排队时间,提升用户体验。这种“不患寡,而患不均”的思想就是负载均衡的基本原理。
负载均衡的分类
通常情况下,负载均衡分为两种:
- 请求负载均衡,即将用户的请求均衡地分发到不同的服务器进行处理;
- 数据负载均衡,即将用户更新的数据分发到不同的存储服务器;
数据分布算法很重要的一个衡量标准,就是均匀分布。可见,哈希和一致性哈希等,其实就是数据负载均衡的常用方法。因为这些方法在上篇文章中已经讲述,所今天, 我就与你着重说说服务请求的负载均衡技术吧。
请求负载均衡
在分布式系统中,服务请求的负载均衡是指,当处理大量用户请求时,请求应尽量均衡地分配到多台服务器进行处理,每台服务器处理其中一部分而不是所有的用户请求,以完成高并发的请求处理,避免因单机处理能力的上限,导致系统崩溃而无法提供服务的问题。那么,它又是怎样去实现的呢?
请求负载均衡的方法
一般来说,在计算机领域中的不同层有着不同的负载均衡的方法,例如网络层通常有基于DNS,IP报文等的负载均衡方法;在中间件层常见的均衡策略主要包括轮询策略、随机策略、哈希和一致性哈希策略等等,而中间件层也就是我们所说的分布式系统层是我们今天着重去分析的。接下来,我们就具体看看吧。
轮询策略
轮询策略是非常简单的且很常用的一种负载均衡策略,目的就是让服务器轮流处理用户请求,尽可能的让各个服务器处理的请求数相同。用一个很形象的例子来表达就是:学校中打扫卫生总是会让某个班级轮流去打扫一片区域,这就是轮询。
那有的人就有疑问了,在学校打扫卫生如果打扫的不干净或者别的原因会处罚多次打扫,对于这种惩罚性的措施是不是要特殊处理呢?其实这种也是轮询,但是因为需要处理,所以我们把它称之为加权轮询。说到这我们就知道了轮询策略其实是分为两种的:顺序轮询和加权轮询。
首先我们来看下顺序轮询,假设我们有6个请求,编号分别为1-6,有三个服务器去处理请求,编号为1-3,如果我们采用顺序轮询策略的花,服务器会按照123顺序轮流进行请求,大致步骤如下图所示。
步骤 | 请求编号 | 选择的服务器编号 |
---|---|---|
1 | 1 | 1 |
2 | 2 | 3 |
3 | 3 | 3 |
4 | 4 | 1 |
5 | 5 | 2 |
6 | 6 | 3 |
最终的处理结果是,服务器1处理请求1和请求4,服务器2处理请求2和请求 5,服务器3处理请求3和请求6。
那什么是加权轮询呢?首先,加权是我们需要增加一个优先级,还是上边的例子,这次我们增加一个优先级,服务器1-3分配了优先级{4,1,1},这6个请求过来的时候还当成6个步骤,如图所示。
步骤 | 请求编号 | 选择的服务器编号 | 各服务器优先级 |
---|---|---|---|
1 | 1 | 1 | {3,1,1} |
2 | 2 | 1 | {2,1,1} |
3 | 3 | 1 | {1,1,1} |
4 | 4 | 1 | {0,1,1} |
5 | 5 | 2 | {0,0,1} |
6 | 6 | 3 | {4,1,1} |
大致步骤就是在优先级确定的情况下,每来一个请求会把服务器优先级减1,当变为0后就轮询下一个服务器,最后都减为0之后重新开始。
最终的处理结果是,服务器1处理请求1~4,服务器2处理请求5,服务器3会处理请求6。当然这种加权轮询只是很基础的一个策略,我们在实际应用中可以根据自己的需求去作出相应的改变,例如Nginx 默认的负载均衡策略就是一种改进的加权轮询策略。
总结一下,轮询策略的优点就是,实现简单,且对于请求所需开销差不多时,负载均衡效果比较明显, 同时加权轮询策略还考虑了服务器节点的异构性,即可以让性能更好的服务器具有更高的优先级,从而可以处理更多的请求,使得分布更加均衡。而缺点是每次请求到达的目的节点不确定,不适用于有状态请求的场景。并且,轮询策略主要强调请求数的均衡性,所以不适用于处理请求所需开销不同的场景。所以,轮询策略适用于用户请求所需资源比较接近的场景。
随机策略
随机策略也比较容易理解,指的就是当用户请求到来时,会随机发到某个服务节点进行处理,可以采用随机函数实现。这里,随机函数的作用就是,让请求尽可能分散到不同节点,防止所有请求放到同一节点或少量几个节点上。
这种方式的优点是,实现简单,但缺点也很明显,与轮询策略一样,每次请求到达的目的节点不确定,不适用于有状态的场景,而且没有考虑到处理请求所需开销。除此之外,随机策略也没有考虑服务器节点的异构性,即性能差距较大的服务器可能处理的请求差不多。
因此,随机策略适用于集群中服务器节点处理能力相差不大,用户请求所需资源比较接近的场景。
那么对于轮询策略和随机策略都不能定位到同一个服务器的问题我们该怎么处理呢?首先我们来看一个为什么需要落到同一个服务器的例子,比如我们这台服务器是缓存服务器,那么就会对缓存同步带来巨大的挑战,尤其是系统繁忙时,主从同步比较慢,可能会造成同一客户端两次访问得到不同的结果。解决方案就是利用哈希算法定位到对应的服务器,接下来我们就看一看哈希算法。
哈希和一致性哈希策略
听到这个名字你可能会很熟悉,因为我们在之前的《分布式存储》一文中已经讲解过两个算法。当时说数据分布算法的均匀性,一方面指数据的存储均匀,另一方面也指数据请求的均匀。这里的数据请求就是用户请求的一部分,所以说哈希、一致性哈希、带有限负载的一致性哈希和带虚拟节点的一致性哈希算法,同样适用于请求负载均衡。因为之前的文章已经对这几种算法作出介绍,此处不再赘述。
那么,哈希与一致性策略的优点是什么呢?哈希与一致性策略的优点是,哈希函数设置合理的话,负载会比较均衡。而且,相同 key 的请求会落在同一个服务节点上,可以用于有状态请求的场景。除此之外,带虚拟节点 的一致性哈希策略还可以解决服务器节点异构的问题。同样,它的缺点是什么呢?我们之前在介绍哈希和一致性哈希算法的时候有说过,当节点故障时候的处理存在数据迁移(哈希)和数据倾斜(一致性哈希)的问题,所以这两种策略也没考虑请求开销不同造成的不均衡问题。
除了以上这些策略,还有一些负载均衡策略比较常用。比如,根据服务节点中的资源信息 (CPU,内存等)进行判断,服务节点资源越多,就越有可能处理下一个请求;再比如, 根据请求的特定需求,如请求需要使用 GPU 资源,那就需要由具有 GPU 资源的节点进行 处理等。
下期预告
【分布式系统遨游】分布式缓存
关注我们
欢迎对本系列文章感兴趣的读者订阅我们的公众号,关注博主下次不迷路~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。