最近,我一直在考虑有关Envoy代理控制平面的问题,因此我认为这些问题与我分享有关行业现状以及未来几年技术发展的一些结论是很有用的。
现状
尽管我一直在与Envoy用户交流,但现在,我们每年一度的EnvoyCon / KubeCon对于我来说都是一个重要的检查点,因为我试图围绕 在一线部署Envoy
面临的各种问题。尽管我可以通过Lyft的部署来获取此类信息,但是拥有更多的数据点使我可以更好地了解项目,并且可以开展的最重要的事情,从而更好地满足最广泛的用户需求。
在参加了最近的EnvoyCon/KubeCon并花了一些时间思考我所学到的知识之后,一些高级要点对我来说变的清晰:
- 尽管基于Envoy的
开箱即用
服务网格和API网关解决方案(例如Istio及其衍生产品,Kuma,Consul Connect,App Mesh,Traffic Director,Ambassador,Contour等)的数量仍在不断增加,这些产品正处在前沿。我指的是前沿,这是早期阶段,现在大多数尝试使用它们的部署都相对较小,并且通常是未开发的。 - 同时,我保守地估计,现在有数百个组织在部署基于Envoy的服务网格和API网关解决方案时,使用直接针对xDS API(通常构建在go-control-plane之上)编写的自定义私有控制平面,一些规模非常大。
- 所有部署自定义控制平面的组织都在一次又一次地独立解决许多相同的分布式系统问题,而没有从协作开发,学习和强化的能力中受益。
在以下各节中,我将更详细地探讨上述每一个要点,然后讨论我认为作为一个项目在近期内实用地帮助最大数量的Envoy大规模用户时可以做的事情。
绿地与棕地的现实
指全新功能和遗留功能
当前的大多数云原生生态系统都是一个闪闪发亮的地方,主要假设为未部署地区。在这种情况下,未开发的项目意味着从头开始,要设计和测试一组可以很好地协同工作的云原生技术。尽管作为一个行业,我们当然要使易于使用的全新云本机系统还有很长的路要走(我正在为您介绍大量的YAML),但我们在使架构模块稳定方面取得了长足的进步。另一方面,已经大规模部署了遗留技术的大型组织则完全面临着一个不同且更为复杂的问题:尝试在不将用户与新用户之间进行过渡的情况下,将旧与新联系起来。
以Lyft为例,我们的 legacy
计算栈是一个定制的构建/部署系统,它使用原始EC2虚拟机,自动伸缩组等。我们最初的基于Envoy的服务网格和API网关紧密地集成在其中系统及其所有固有架构。在过去的几年中,Lyft进行了向Kubernetes的迁移。除了讨论这种迁移是否产生正的ROI之外,这种迁移的技术要求是巨大的。我们建立了一种机制,将我们的旧系统和新系统桥接到一个统一的计算平台中,从而允许服务在两者之间同时透明地运行,从而实现安全的计算迁移。几乎可以想象,如果不进行大量修改就可以将 开箱即用
的Envoy服务网格解决方案之一用于此目的。(有关Lyft如何将其服务网格适应Kubernetes的更多信息,请参见丽塔·乔(Lita Cho)和汤姆·瓦尼尔斯塔(Tom Wanielista)的精彩EnvoyCon演讲。)
我们在云原生空间中面临的最困难的问题之一是在可配置性与复杂性和可用性之间取得平衡。解决方案越是,它所需的配置就越少,(至少在理论上)它就越复杂。在这方面,未开发的解决方案,尤其是PaaS和FaaS,具有重要意义。他们可以对计算堆栈,部署工具,网络等做出各种假设,从而使他们能够大大减少所需的配置,从而降低复杂性并提高可用性。
作为一个项目,Envoy从未尝试将简化配置作为主要目标。我们假设Envoy是用于大量部署和垂直产品中的工具。这种假设对我们不利,因为有时会出现一些迷惑的用户,这些用户来到我们的文档和API中,却不知道从哪里开始。同时,Envoy 丰富的API一直是其在业界迅速采用的背后推动力之一,我认为这是一个富有成效的折衷方案。要点是,可配置性与复杂性之间的关系是一个滑动比例,不可能让每个客户都满意,因此必须采用分层的方法来组成系统。
在这方面,构建在Envoy之上的各种服务网格和API网关正在以务实的方式进行分层:它们将Envoy用作构建块,并在顶部创建 更简单
,更自制的平台。但是,如前所述,简化与可配置性是不一致的,因此使这些解决方案在更复杂的遗留部署(例如Lyft's)中工作要复杂得多(如果不是不可能的话)。
Lyft的故事并不少见,这代表了为什么Envoy最经常通过内部编写的专有定制控制平台在整个行业中广泛部署:这些组织中的每一个都独立决定,对于遗留部署,完全控制更为有效通过Envoy xDS API和驱动它的控制平面代码。
常见控制平面问题
大多数组织会在3-5年内仍在编写定制的Envoy控制面吗?我对此表示怀疑。在这段时间内,我们将看到更多向标准云原生技术的迁移,并且自此以后,许多当前的新建系统将成为大规模部署。在这样的未来世界中,我希望大多数部署都将使用当今正在开发的一种垂直解决方案。然而,在此期间,事情很混乱。大规模遗留部署的现实正在推动用户开发定制的Envoy控制平面解决方案,所有这些都面临着类似的大规模问题。这些问题包括:
不变的基础架构推动了高系统变更率
不可变的基础架构计算系统(例如Kubernetes)通常会导致很高的系统更改速度,因为容器会由于自动缩放,部署,批处理作业等而快速创建和终止。Lyft的经验一直是,更改率可以是甚至超出我们的旧系统所发生的数量级。计算/网络拓扑中的高变化率给控制平面带来了很大压力。如果不注意,原生的实现很容易受到失控的拓扑计算的影响。
在控制平面中实施常见的分布式系统最佳实践
Envoy控制平面必须实现大量标准的分布式系统最佳实践。这部分是由于基础架构不可变导致系统更改率很高,另一部分是由于规模的现实性。这些最佳做法包括:
- 速率限制:确保控制平面不会对请求过多的后端配置发现系统进行轰炸(K8s API,Consul,Zookeeper等都容易受到类似DoS场景的影响)。
- Batching:确保控制平面不会因顺序更新过多而使每个Envoy都无法正常运行。尽管这在高变更率系统中特别重要,但控制平面通常需要批量处理配置发现系统接收到的更新。请注意,尽管Envoy本身在内部进行了类似的批处理以避免损坏数据平面工作线程,但这通常是不够的,并且仅是对要求高系统更改率的控制平面的适度防御。
- 背压(Back pressure):控制平面需要检测传入的Envoy客户端连接或配置发现系统在短时间内发布过多更新的时间是否过载。在承压期间,控制平面需要开始删除更新,并具有未来同步的机制,并确保所有Envoy最终都收敛于系统的目标状态。
- 缓存:为了在给定数量的客户端的情况下保持高性能,大多数控制平面最终都实现了一定数量的缓存,以避免为每个客户端独立地从配置发现系统获取世界状态。正确实现缓存并不是没有很大的挑战,尤其是在使用Envoy的基于推的xDS变体时。
大规模控制平面功能,包括增量xDS和端点子设置
在足够大的系统规模上,将服务的每个端点发送给每个下游客户端变得不可行,原因如下:
- 如果使用客户端主动健康检查,则可能导致N^2健康检查爆炸。
- Envoy的内存使用量与其连接的上游端点的数量成线性比例关系。因此,大量的上游端点导致内存使用增加以及连接池使用效率低下。
简单
控制平面通常使用State-of-The-World(SoTW)xDS API,这意味着只要控制平面中的任何资源发生更改,控制平面都会发送该资源集合的完整快照。即,如果添加或删除了群集中的单个端点,则控制平面需要在使用SoTW时将群集中的每个端点发送给Envoy。这导致小更新需要大量的CPU和网络带宽。
前两个问题的解决方案是双重的:
- 子集:使用下游和上游服务的已知拓扑,控制平面可以将上游端点的子集发送给每个下游客户端,以使每个端点上的总体负载保持相似。
- 增量/增量xDS:每个xDS API都实现了SoTW和增量变量。增量xDS允许控制平面将增量发送给每个客户端,但代价是实质上增加了控制平面的复杂性,因为控制平面需要跟踪每个已连接客户端的状态。但是,实施增量更新将极大地减少对每个客户端执行小更新所需的CPU和网络带宽。
- 前面两个解决方案中的每一个在实践中都很难实现。
控制平面调试和可观察性
大规模运行控制平面的调试和可观察性要求与大规模运行Envoy并无显着差异。了解控制平面及其缓存的状态,配置是否已收敛,当前配置是什么等至关重要。尽管实现此类调试和可观察性功能并不复杂,但每个大规模部署Envoy的组织都在此过程中重复了这项工作。略有不同的方式。
开放更多的控制平面工程
如果我们假设,正如本文所概述的那样,由于组织最终会集中在垂直解决方案和产品上,因此在未来3-5年内部署Envoy将会很混乱,那么作为社区,我们可以做些什么来使每个人都更容易部署Envoy控制面板目前正在编写自定义解决方案?
将更多功能移至控制平面
在去控制平面的项目已经存在了相当长的一段时间,可以用来加速基于转到特使控制平面的开发库。该库提供了控制平面需要支持的内容的概要,包括缓存,配置交付等。它还处理了将Envoy的protobuf API编译为Go代码的艰巨任务。
但是,go-control-plane是一个非常薄弱的库,并且当前不提供上述任何分布式系统最佳实践功能,也不执行子集或增量/增量xDS。
我经常被问到Lyft是否会开源我们的控制面板。答案是否定的,主要是因为纠结于我在之前的文章中描述了遗留问题。对于控制面内置的Lyft的传统基础架构和业务逻辑,有太多的假设。毫不奇怪,使用Envoy的Lyft规模以上的每个组织都说类似的话。
我认为Lyft和业界都可以做的就是将更多功能移到go-control-plane中,以便库本身变得更加有用。这包括速率限制,批处理,反压力,增强的缓存,参考Kubernetes和Service Mesh Interface(SMI)实现等,这显然对希望使用其他语言构建控制平面的组织没有帮助,但是成为云原生开发的通用语言(不管喜欢与否),这似乎是一个合理的折衷方案。将更多功能转移到库中不会产生新的服务网格产品,但会产生更可靠的基础,我们可以共同协作,发现错误并强化。
开发xds-relay
除了增强go-control plane的即用型功能之外,我们还启动了一个名为xds-relay(设计文档)的项目。考虑xds-relay的最简单方法是,它是Envoy配置的CDN。我们相信可以创建一个独立的服务器(在go-control平面上构建),该服务器可以部署在任何xDS兼容的控制平面“原始”服务器之前。中继将是一个横向扩展组件,通过在一个开放源代码的地方实施本文中概述的所有分布式系统最佳实践,可以帮助大型Envoy部署实现高可用性。
此外,一旦完成xds-relay MVP(简单的缓存和横向扩展),社区就可以在其他功能上进行协作,例如:
- 当前状态(SoTW)到增量/增量XDS转换:可以在继电器中创建SoTW到增量转换代码,从而使原始控制平面保持简单,并将增量逻辑委托给共享的开放源代码。
- Automatic endpoint subsetting:中继将通过原始xDS构建块(如群集,端点等)了解整个系统拓扑。因此,中继应可选地能够直接执行端点子集,而无需原始控制平面意识到这一点。
- xDS translation hooks:经常需要对Envoy配置通过控制平面管道进行转换进行转换。中继将是可以选择执行此操作的公共位置。
- API驱动的中继配置更新:中继的设计目标之一是它只会使用原始xDS。话虽如此,没有什么可以阻止中继最终成为API驱动的控制平面本身。在这个地区有许多有趣的方向可以探索!
通过将构建Envoy控制平面的大部分复杂性转移到开放源代码中,我们所有人可以一起协作,一起查找错误并一起强化实现,从而使专有/内部部分的推理更加容易。这对每个人都是双赢。如果您有兴趣帮助继电器开发,请与我们联系!
结论
Envoy在行业中的迅速普及已经创造了许多垂直产品和服务,还创造了数百种定制的定制控制面。很明显,许多具有自定义控制平面的组织不会很快放弃它,而是采用简化的服务网格和API网关解决方案,但是它们也冗余地解决了同一套分布式系统和扩展问题。明年,通过go-control-plane增强和xds-relay等项目,我们可以改善Envoy普通用户的现状,并提高垂直产品和服务的稳定性,这些产品和服务最终将被利用为构建模块。
原文 https://mattklein123.dev/2020/03/15/on-the-state-of-envoy-proxy-control-planes/