Aws - Application Load Balancer - algorithms (翻译)

1,466 阅读6分钟

Aws - Application Load Balancer - algorithms

原文地址: medium.com/dazn-tech/a…

注:在原文基础上做了部分的修改,如介意请浏览原文。

在2019年以前,AWS Application Load Balancers (ALBs)仅支持轮询路由算法(round-robin),而现在aws提供了一种新的算法 Least Outstanding Requests (LOR) algorithm(最少未完成的请求 )

什么是 balancing algorithm?

基本上所有的负载平衡器都支持负载平衡算法,简单来说,负载平衡算法用于映射不同请求到相应的目标。使用正确的算法往往能有效的提升性能。而使用最普遍的两个算法就要属 round-robin(轮询)least connections(最少连接)(在aws中称为最少未完成的请求算法)

轮询算法(Round robin)

轮询算法最为简单,按照循化依次访问你的目标组,这样每个目标组都会收到相同数量的请求,由于他的简单性,几乎所有的负载平衡器都支持轮询算法。

1_Gb7hi5pqKmYYxEIUCJylHw.gif

轮训算法的优点

  • 简单易用
  • 分配合理,均衡

轮训算法的缺点

  • 每个目标组需要具有相似的算力,资源或者性能
  • 每个请求所获取的目标组的算力,资源,性能和延迟几乎相同

针对最后一点,这也是轮训算法最重要的缺点。API有很多种类型,每个方法都会导致不同的负载量。例如,POST 请求通常比 GET 请求需要更多的资源。从上图可见,任务1可能在收到另一个请求时仍在处理前一个请求。任务2可能在较慢的硬件上运行。在使用云资源时,无法保证每个实例的性能相同。更糟糕的是,如果我们使用 Spot 队列,我们将运行不同大小的实例,每个实例具有不同的性能和容量。

最少未完成的请求算法 (Least Outstanding Requests)

最少未完成的请求算法可以解决轮训算法的缺点。他每次选择目标组时,会去寻找当前等待请求最少的目标组,而不是循环访问。在 nginx 中这种算法名叫 least_conn

下图显示了LOR算法如何引导请求。这里OR表示未完成请求的数量,我们每次都会选择OR值最小的目标组作为选择,在选择过后,OR 的数值增加1。然后再接待下一个请求,再次寻找 OR 最小的目标组,以此反复。

1_yS5wbfjnPF0ic67bnd9w7A.gif

扩展后重新平衡集群对于基于 WebSocket 的服务至关重要,例如我们的大规模处理WebSockets的产品Pubby。有关使用 ALB 扩展 WebSockets 服务的更多信息,请阅读该文章的负载测试部分。

对于基于 HTTP 的服务,LOR 算法仍然会对性能产生巨大影响。让我们对这些算法中的每一个运行负载测试,看看有什么区别。

负载测试

为了查看使用这些算法时的性能差异,我们将使用 Artillery 在一个简单的 Node.js 应用程序上运行负载测试

我们的测试服务将有 2 条路线

  • GET /test— 立刻返回成功
  • POST /test — 在等待随机 0-200ms 后返回成功。

Artillery 配置: (Artillery 配置运行 120 秒的负载测试,以每秒 10 次运行命中服务,每次运行 3 个 GET 请求和一个 POST 请求)

config:
  target: ""
  phases:
    - duration: 120
      arrivalRate: 10

scenarios:
  - flow:
      - loop:
          - get:
              url: "/test"
        count: 3
      - post:
          url: "/test"

Application code

const http = require('http');
http.createServer((req, res) => {
  if (req.method === 'POST') {
    let now = Date.now();
    const finish = now + Math.random() * 200;
    while (now < finish) {
      now = Date.now();
    }
    res.writeHead(200, {
      'Content-Type': 'application/json',
    });
    res.end(JSON.stringify({ success: true }));
  }

  if (req.method === 'GET') {
    res.writeHead(200, {
      'Content-Type': 'application/json',
    });
    res.end(JSON.stringify({ success: true }));
  }
}).listen(8080);

结果来看,LOR算法明显更优,先贴上测试结果。

Round-robinLeast Outstanding RequestsPerformance Improvement
Median68.554.725.23%
P951062.4217.2389.13%
P992374386.4514.39%

下面介绍几个测试中的专业术语:

  • Latency(延迟): 是衡量服务器响应客户端请求的速度。通常以毫秒 (ms) 为单位,延迟也通常称为响应时间。较低的数字表示更快的响应。延迟是在客户端测量的,从发送请求到收到响应。网络开销包也含在此数字中。
  • p99指标:反应速度排名前百分之99的所有请求的平均延迟的数值需要满足指标。(要求最严格,几乎相当于每个请求都需要满足指标)
  • P95指标:反应速度排名前百分之95的所有请求的平均延迟的数值需要满足指标。(反应最长时间的%5请求们,就不算在统计中了,稍微宽松)

知道了这些指标后再看上图可知,当统计所有request(P99)时,Least Outstanding Requests相对于Round-robin的延时提升了很多,我们可以理解为Round-robin的长延时请求数量极大。

LOR算法的缺点

使用 LOR 算法的主要风险是当新目标添加到目标组时会导致大量请求。在上面的 LOR 图中,任务 6 快速连续收到 5 个请求,这可能会使它处于高负载下。这在运行 WebSocket 服务时存在风险,因为当我们每秒接收数千个连接时,我们不希望所有新连接突然被发送到单个任务。 HTTP 服务不应该受到那么严重的影响,但仍然值得考虑。

ALB 支持慢启动,它指示 ALB 缓慢增加新目标将服务的请求数量。但缺点是,不能同时使用 LOR 和慢启动。避免此问题的唯一方法是确保我们的自动扩展策略在每次扩展操作期间至少启动几个任务。

另一个潜在问题是,失败的目标通常比健康的目标响应速度更快。例如,如果您的服务未连接到数据库,它可能会立即响应 500 错误。在这种情况下,失败的目标将收到更高比例的请求,从而导致更多的失败事件。因此,确保运行状况检查能够快速对失败的目标做出反应非常重要。这仍然会导致至少 10 秒的失败请求,因此也可能值得引入一些人为的错误延迟。希望 AWS 能够改进他们的健康检查,以便我们可以更快地将流量从失败的实例中转移出去。

总结

总之,LOR算法通常会减少延迟。它有助于平衡整个集群的资源利用率。