八股复习Day 2.负载均衡算法

25 阅读6分钟

image.png

当大量的用户请求同时打到一台服务器上的时候,这台服务器很可能会承受不住压力,导致宕机。上一篇文章八股复习Day 1.限流器介绍的限流是保护服务的办法;负载均衡是另一种保护服务的办法。

负载均衡,通过将请求均匀的分配到几台服务器上,防止压力集中在一台服务上,打垮服务。负载均衡算法主要分为服务端负载均衡客户端负载均衡(本文不涉及硬件负载均衡)

这两种负载均衡有什么区别呢:

  • 服务端负载均衡:当客户端发起一个请求,请求会先打到服务前面的一台负载均衡服务器(nginx,lvs等);然后负载均衡服务器会通过算法,找到并将请求分发到提供这个服务的服务器

image.png

  • 客户端负载均衡:服务端通过将服务注册到注册中心(zookeeper/etcd/硬编码),客户端可以获得所有提供这个服务的服务器列表。当我们在代码中访问一个服务,通过负载均衡算法从列表中选择一台服务器进行请求。

image.png

简而言之,这两种负载均衡的区别主要在于调用的这条链路中,有没有通过一个第三方的负载均衡服务

服务端负载均衡:客户端——>负载均衡服务器——>服务器  
客户端负载均衡:客户端——>服务器

常见的负载均衡算法可以分为: 随机,轮询,哈希,最小压力等,下面分别介绍一下

随机

随机就是没有规律的从负载中获得一台,又分为完全随机和加权随机

  • 完全随机的实现很简单,通过生成一个随机数来选择机器即可; 但缺点也很明显,不同的机器性能,处理能力不一样,完全随机不能很好的利用这些资源
  • 加权随机,根据机器的性能分配不同的权重,被选中的几率就会高一些

轮询

轮询又分为三种,1.完全轮询 2.加权轮询 3.平滑加权轮询

  • 完全轮询:类似完全随机,维护一个服务器列表,轮流使用其中的机器(1,2,3,4)

  • 加权轮询:类似加权随机,权重高的服务器相当于在服务器列表里有多份,能更多的轮询到(1,1,2,2,2,2,3,4)

  • 平滑加权轮询:加权轮询存在一个问题,权重高的机器可能会压力突然上升,而其他的机器却是空闲状态

    • 平滑加权是一个很巧妙的算法,可以很好的解决加权轮询的缺陷 假如我们现在有三台服务器
    序号IP权重
    1127.0.0.15
    2127.0.0.21
    3127.0.0.31

如果是加权轮询,那么前5次都会选择机器1,然后才会选择机器2机器3

而平滑加权的选择流程如下

假设我们有 N 台机器 S = {S1, S2, …, Sn}(例子中的1,2,3),

配置权重 W = {W1, W2, …, Wn}(例子中的5,1,1),所有实例的配置权重和为 weightSum

有效权重 CW = {CW1, CW2, …, CWn}(实际轮询时使用的权重,CW 初始与 Wi一致)

currentPos 表示当前选择的实例 ID

  1. 初始每个实例 i 的 当前有效权重 CWi 为 配置权重 Wi,并求得配置权重和 weightSum;
  2. 轮询会选出 最大CWi 对应的的实例,currentPos 指向此实例;然后将 当前有效权重 CWi 减去所有实例的 权重和 weightSum
  3. 将每个实例 i 的 当前有效权重 CWi 都加上对应的 配置权重 Wi
  4. 此时变量 currentPos 指向的实例就是需调度的实例;
  5. 每次调度重复上述步骤 2、3、4;

以上面的例子为例

次数选中前的有效权重CWcurrentPos选中的实例选中后的当前权重(步骤2)更新有效权重(步骤3)
1{5, 1, 1}0127.0.0.1{-2, 1, 1}{3, 2, 2}
2{3, 2, 2}0127.0.0.1{-4, 2, 2}{1,3,3}
3{1,3,3}1127.0.0.2{1, -4, 3}{6,-3,4}
4{6, -3, 4}0127.0.0.1{-1, -3, 4}{4, -2, 5}
5{4, -2, 5}2127.0.0.3{4, -2, -2}{9, -1, -1}
6{9, -1, -1}0127.0.0.1{2, -1, -1}{7, 0, 0}
7{7, 0, 0}0127.0.0.1{0, 0, 0}{5, 1, 1}
8{5, 1, 1}0127.0.0.1{-2, 1, 1}{3, 2, 2}

可以看出,平滑加权轮询还是按照权重选择的,但是中间有交叉使用,避免逮着一个服务器薅。

哈希

哈希一般分为:源地址哈希一致性哈希

源地址哈希:

  • 按照请求的来源地址,进行哈希计算并对服务器列表长度进行取模操作,得到的结果就是要请求的服务器序号;对于这种方式,同源的请求总能打到同一台机器上
  • 这种方式的坏处就是,如果一个来源的请求很活跃,所有请求都会打到同一个机器,加重机器的压力
  • 不方便快速进行扩缩容,如果某一台机器宕机了,那么短时间内,某些来源的请求都会失败

一致性哈希: 一致性哈希又对普通的哈希进行了改造,解决了上述扩缩容的问题

1、想象一下我们将服务器的地址或者名称进行hash,哈希的结果会分布在一个环上

image.png

2、当请求来了之后,同样对请求的地址或其他key进行hash,映射到换上;然后顺时针行走,遇到的第一个服务器就是请求的服务器

image.png

3、如果此时发生了扩缩容,服务还是可以正常响应,只是请求有可能打到哈希环上离他更近的节点上了

image.png

4、但同时,哈希环有可能带来不平衡的问题;下图中,A掌控的区域远远大于B,如果请求达到红框附近,都会请求到服务器A

image.png

5、为了解决不平衡的问题,引入了虚拟节点的概念

即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。数据定位的方法和前面说的一样,没有变化。当请求时请求到虚拟节点时,实际上还是达到其对应的真实节点上去

image.png

最小压力

也可以是最小连接,最少并发,最少cpu使用率,最快响应等,根据使用场景使用。

顾名思义,这种方式是通过找到最空闲的机器来进行请求,效果好,但也比较难实现,需要实时监控服务的负载情况,资源情况。