Envoy 实战:几种常见负载均衡算法的性能比较

微信扫一扫,分享到朋友圈

Envoy 实战:几种常见负载均衡算法的性能比较

本文模拟了几种负载均衡算法,并指出其优劣点,帮助大家更进一步了解负载均衡算法。

作者:Tony Allen

翻译:Bach(才云)

校对:星空下的文仔(才云)、 bot(才云)

如果我们在使用网络系统,那么可能会非常关心延迟问题。在面对一组服务器时,我们需要思考选择哪种负载均衡算法。如果可以直观了解不同负载均衡器配置的具体情况,那对我们做决策将非常有帮助。这样还能最小化环境中的延迟,以避免意外情况发生。

众所周知,负载均衡器主要负责将网络请求分发到服务器集群上(这在 Envoy 中称为上游)。我们一般追求最大化网络请求的服务效率。这意味着服务器的 CPU 利用率更高,并且发送方的等待时间更短(延迟)。通常在有延迟的地方,我们还会发现在某个部位正形成一个队列。因此,我在研究负载均衡器方案,以最小化上游的队列。

本文将简要介绍 Envoy 中的各种负载均衡算法,并通过一些模拟案例来展示它们的表现。这里不讨论重试策略、断路、紧急路由,负载均衡器优先级,以及它们对负载均衡的影响。

K8sMeetup

模拟流量

接下来的每个模拟案例都会通过 Envoy 进程将具有固定 RPS 的 HTTP 请求发送到由 10 个 HTTP 服务器组成的集群上。 服务器接受一个请求后,会休眠一段时间(我们称其为“服务时间”),再以 200 状态进行响应。

模拟的一般拓扑结构

如果特定服务器同时处理多个请求,它将反复随机选择一个,并休眠 100us,直到满足该请求的“服务时间”,这近似体现了并发请求对延迟的影响。当每个服务器都形成队列并为多个请求提供服务时,每个请求的响应时间将增加。需要注意的是,如果我们没有让每个请求都具有相同的休眠时间,并且没有实际的延迟分布,那么服务器上的排队将对尾部延迟造成相当的影响。

延迟和 RPS 编号的细节这里就不讨论了,因为我们关心的是队列的形成原因,以及队列与负载均衡算法之间的关系。由于我们在控制 RPS 和请求延迟,因此只有两者之间的关系才对排队行为有影响。

现在,让我们来看个好东西 —— 负载均衡器!

K8sMeetup

随机负载均衡

Envoy 支持的最简单的负载均衡器是随机负载均衡器,它的节点、端点是通过随机选择决定的。 随机法是将请求分发到一组上游节点的最简单方法,也是最容易实现的方法。 100 万个选择在通过同一个随机选择算法处理后,将会均匀地分布在 10 个节点池中:

使用随机选择 的节点分布直方图

请求均匀地分配了!这样就好了么?

并非如此简单。让我们看一下通过随机负载均衡的 10 个节点请求分配情况。

下图是我们的模拟结果,其中每条线代表一个不同的端点,Y 轴是在模拟过程中,特定时间点该端点未完成的请求数:

每个节点对随机 LB(负载均衡)活跃请求数

每个端点的活动请求数并不重要,但是我们要注意是端点之间请求的分布情况。在某些特定时间点,一些节点未完成请求数要比其他节点高一个数量级!这说明,即便随机法看似实现了均匀分布,但部分节点在某些时间点仍存在负担过重的情况。这将导致延迟增加,形成服务中的请求队列,最后造成连锁故障。

因此我们引入轮询策略,以确保每个节点以可预测的方式接收请求,来解决上述问题。

K8sMeetup

轮询负载均衡

Envoy 的轮询负载均衡策略是按顺序循环通过每个上游节点。 这种策略的好处是不仅可以统一随机选择,还能于任意时间点都提供可预测的请求分布。 我们通过相同的模拟,可以发现与上面的随机选择测试结果相比,使用轮询负载均衡策略后,上游节点之间的活动请求分布会更加平均:

每个节点对轮询 LB(负载均衡)活跃请求数

我们还在模拟中比较了轮询负载均衡和随机负载均衡分别每个节点上的请求数。通过比较每个时间点接收到最多请求的节点与最少请求的节点之差,我们定义了一个称为“请求偏移”的度量标准:

每活跃请求数最高节点与活跃请求数最低节点之间的差异

完美!使用轮询负载均衡算法以最小的活跃请求数偏移来实现均匀分配请求!简单而又有效!

那么轮询就是最完美的负载均衡算法吗?不见得。

到目前为止,所有上游节点都具有相同的延迟配置。如果上游的某些节点性能非常强大,那他们就得不到充分利用。下面,我们进行了相同的轮询模拟。现在有 3 个性能强劲的节点立即完成了请求,但 3 个性能较弱节点完成请求的速度比以前慢了 25% 。如下图,有 3 个明显的活跃请求数分组:

高延迟/弱节点(A)、标准节点(B)和快速节点(C)的活跃请求数

我们现在遇到的问题是,A 组中较慢的(性能薄弱)节点因为一次处理太多请求出现了较高的延迟,而 C 组中性能好的节点没有充分利用。我们可以注意到,处理速度较慢的节点,请求队列不断增长(可能导致连锁故障),而处理较快的节点,基本上没有队列。

如果负载均衡器可以计算每个节点未完成的请求数量,并对此调整分发策略,那就太好了!

恰好,Envoy 有一个负载均衡器可以做到这一点!

K8sMeetup

使最小连接负载均衡

Envoy 的最小连接负载均衡器考虑了发送给每个节点未完成的请求数量,并会根据活跃的请求数量对其分发策略进行调整。 讨论轮询方法时,我们会遇到过度使用或未充分利用节点的问题。 但这里有个细节很重要“偏向”节点的选择到底要怎么做?

考虑分配给该节点的权重与该节点未完成请求数成反比。如果我们有 100 个权重在[0,100]范围内的节点,现在有几种不同的方法根据权重对选择进行“偏向”。

加权比例选择

最明显的加权选择方法就是让对象的选择概率与权重成正比,就像轮盘赌博。这也称为适合度比例选择。通过模拟,我们可以看到选择数比例与选择池中每个对象的权重成正比(x 轴是对象的权重):

加权比例选择在不同时间点的选择数直方图。X 轴每个对象权重代表具有相应权重的单独对象

其实,与对象权重成正比的选择概率是一把双刃剑。这种选择方法很好,因为负载均衡器可以向请求较少的节点发送更多请求,响应也更快。但是,在负载均衡池中的所有节点都重新排列并且还插入新节点情况下,这可能会导致一些问题(就像下述放大事件中所展示的)。虽然这不是大家熟悉的 thundering herd 问题,但肯定属于同一类。

如果我们有 9 个权重在[0,9)范围内的节点和一个权重为 1000 的节点,则可以观察到此现象:

每个 加权比例选择在不同时间点的选择数直方图

我们可以看到,与其他节点相比,这个高权重的节点具有压倒性优势。如果不仔细,我们甚至注意不到其他 9 个节点的存在。有人可能认为这无所谓,但这会导致第 10 个节点立刻开始排队,并且其权重会进行相应调整。这是对的。但我们应该知道,决策是由许多不同的负载均衡器中共同做出的,因此这个高权重节点将收到来自每个负载均衡器的大量流量。

因此,我们需要一种有偏置的选择算法,该算法要能适应羊群行为,同时还要优先考虑权重较高的节点。幸运的是,Envoy 已经有了负载均衡算法。

两种选择的力量(P2C)

假设我们随机选择两个节点,然后选择了权重较高的一个。这种简单而有效的偏向选择方法通常被称为“两种选择的力量(P2C)”,这是迈克尔·米森马赫(Michael Mitzenmacher)在其 2001 年的论文中提出的。

现在使用 P2C 选择,让我们看一下刚刚的两个模拟结果。我们可以看到现在仍然偏向权重较高的节点:

P2C 在不同时间点的选择数直方图。X 轴每个对象权重代表具有相应权重的单独对象

但更重要的是,P2C 选择不会表现出由于权重比例选择而导致的羊群行为!我们可以明显看到池中的其他对象:

P2C 在不同时间点的选择数直方图

这个对于 Envoy 最小连接负载均衡器的应用程序非常符合我们的期望。我们只想向活跃请求较少的节点发送更多请求,并通过因此增加的 RPS 来创建与集群中其他节点一致的队列。此外,P2C 的时间复杂度是恒定的,与权重比例选择的线性情况不同。

Envoy 对 P2C 的实现允许可配置的选择数。因此从理论上讲,我们能通过负载均衡器对节点进行完整扫描,并每次都选择请求量最少的节点。在某些应用中这会非常有用。本文认为,执行两个以上的选择几乎没有好处。因为每次通过执行额外的选择,都将更趋向于羊群行为,因此 Envoy 的最小连接负载均衡器的默认配置执行两个选择。

高延迟节点、标准节点和快速节点的活跃请求数

完全不一样了!在具有不同延迟特性的不同节点之间,活跃请求的分布更加均匀。通过轮询法向所有节点发送相同数量的请求时,我们可以看到最小连接负载均衡器向不同组的节点发送不同数量的请求。这完全基于每个节点的活跃请求数,并将它们保持在相同范围内:

每个节点接收到的请求数

让一个负载均衡器管理所有的这些?

如果我们是想在负载均衡请求时,让跨集群中的所有节点保持一致的延迟,那么使用 Envoy 最小连接负载平衡器是非常安全的。这并不是说它总是最有效的。同样存在着最小连接负载均衡也不好用的情况。在本文中,我们设置了一个简化的客户端/服务器模拟环境,该环境具有最少的附加 Envoy 配置和简单的服务器行为。这些额外的复杂性引起的问题不会引起像随机或轮询负载均衡那样的排队问题。

这样会有哪些问题?

如果某些应用程序更关心在可预见的延迟上平均分配请求,该怎么办?在进行加权负载均衡时,请求粘性问题或特定行为问题呢?在这种情况下(尤其是考虑与重试策略、断路、紧急路由、负载均衡器优先级等情况进行交互),最小连接负载均衡策略并不总是符合要求。还有一种情况,如果有非常多的客户端在缓慢地向少量上游发送请求,那么将没有足够的上游负载信息来正确选择它们,我们只能进行随机进行负载均衡!

我们甚至可以想象这样一种情况:单个节点因为故障所以失败请求速度极快,这导致它会比其他节点更快完成服务,因此,最小连接负载均衡器还会偏向该故障节点,造成成功率下降(虽然实际上,异常检测会阻止该故障节点)。

本文简述了一些使用 Envoy 配置负载平衡器的基本方法和经验,希望对大家有所帮助。

原文: https://blog.envoyproxy.io/examining-load-balancing-algorithms-with-envoy-1be643ea121c

推荐阅读:

在看点一下

Token ,Cookie和Session的区别–学习笔记

上一篇

MAXHUB线上新品发布在即 或将蝉联智能会议平板…

下一篇

你也可能喜欢

Envoy 实战:几种常见负载均衡算法的性能比较

长按储存图像,分享给朋友