从 Istio 在 CNCF 毕业,看服务网格的架构变迁 | 文末送书
近日(美国东部时间 7 月 12 日),CNCF 通过官网宣布,Istio 正式成为毕业项目,理由是作为一个快速增长的服务网格产品,为该领域增添了更多的终端用户、产品特性和维护者,达到了基金会的最高成熟度。
这距离 Istio 加入 CNCF 也仅仅过去 1 年的时间。
如果将 Istio 诞生的 2017 年看作服务网格元年,那么到今天为止,它已经走过了 6 个年头。
作为该领域的典型代表,Istio 的发展历程可以看做是服务网格的浓缩史。历经多年的演进和迭代,Istio 也从萌新转向成熟,它在流量控制、安全和可观测方面的能力也被越来越多的人所了解。
而服务网格领域的开发者们依然在探索着各种新的可能性。本文会基于服务网格的架构演化来阐述目前有哪些新的产品形态和技术方向值得我们关注。
主流的服务网格产品包括控制平面和数据平面两部分。其中数据平面的构建形态体现了服务网格的主要特征。这是因为所谓网格,指的是由服务间通信链路组成的网络拓扑,以及负责流量控制的代理而组成。业界也主要基于提供核心流控能力的代理组件进行优化和调整。下面我们逐一对目前所出现的各种架构模式进行分析,并探讨它们的优劣和适用场景。
一般来说,典型的服务网格都在使用 Sidecar 作为数据平面,但 Sidecar 模式并不是服务网格所特有的。
Kubernetes 的 Pod 提供了多容器支持,所有伴随应用容器部署的其他容器都可以被称为 Sidecar,如日志收集、追踪代理等。
服务网格将具有流控能力的代理以 Sidecar 部署,从而组成了网格数据平面的基本形态。
相对于传统服务治理方案(本质上是以 SDK 方式提供能力)来说,云原生环境下,借助于 Kubernetes 的能力,以 Sidecar 模式实现流控和治理是非常直接的一种实现思路,在某种程度上解决了传统方案的弊端,因此也成为了标准的服务网格实现方式。SDK 类库或框架具有如下的缺点:
代码侵入:SDK 作为应用的依赖包,必然要以某种方式被应用代码引入,如配置、标注、接口实现等。当然,我们也可以说 Sidecar 也需要侵入到应用所在的 Pod,但相比 SDK 代码层面的侵入来说要轻量的多。
语言绑定:SDK 是基于单一语言构建的,针对不同语言要实现同样的功能,就需要提供多语言的 SDK 包。对于一些功能丰富、实现复杂的框架来说,实现多语言版本几乎不可能。因此,这类框架即便功能强大,也只能作为限定于某种语言的特定产品。
维护成本:作为应用的依赖包,想要完成维护和升级都需要依赖方的配合。因工期、人力资源等问题会导致 SDK 的升级延迟或搁浅,造成版本的不一致,从而导致要花费大量精力在维护层面上。
对于异构系统来说,SDK 很难提供一个统一的、跨语言、跨系统的服务治理解决方案。Sidecar 借机杀入服务治理战场,逐渐成为企业落地时重点考量的选项。到今天为止,绝大多数服务网格产品都以 Sidecar 模式作为数据平面的标准。随着落地实践的普及,Sidecar 的缺点也逐渐被人所熟知:
请求中断:原本服务间直接访问的方式,因为 Sidecar 的引入被切分为了三段,且因为进程外调用的增加,出现网络故障的几率也会增加。其副作用就是增加了调试的难度,开发者在故障发生时需要找到到底是在哪一步链路出现了问题。
延迟:请求从一跳变三跳最明显的问题就是会增加延迟,这也是最被开发者诟病的一点。尽管从一些产品的 benchmark 结果来看,Sidecar 的引入只会增加毫秒级(个位数)延迟,足以应对绝大多数场景。但对性能有极高要求的业务场景(如实时广告展示)来说,延迟损耗成为了放弃服务网格的最主要原因。
资源占用:Sidecar 作为一个独立的容器必然会占用一定的系统资源,多数产品的 Sidecar 代理都尽可能设计的轻量化,仅依靠极少的资源即可启动运行。但对于超大规模集群(如数万个 Pod)来说,巨大的基数也使得资源总量变成了不小的数目。同时,这类集群的网络通信拓扑也更加复杂,配置下发的规模也会让 Sidecar 的内存出现剧烈的增长。
维护成本:和 SDK 一样,Sidecar 同样需要维护的成本。尽管像 Istio 这样的网格产品都提供了自动注入机制,开发者无需手动编写和维护 Sidecar 模版信息,但想要合理使用它还是需要做相应的配置调整。在版本升级时,Sidecar 可以解决 SDK 手动升级的侵入性问题,但依然需要通过 Pod 的重建完成升级,对流量敏感的业务可能会受到影响。
也正因为如此,社区的开发者开始重新思考是否应该将服务网格和 Sidecar 划上等号,同时继续探索产品形态其他的可能性。
Sidecar 本质上是一个服务代理(如 Envoy),通过劫持发送到应用容器的流量从而实现对流量的控制。解决代理模式缺点的方案之一就是 Proxyless,即无代理模式。其核心理念是:服务间总是要选择一种协议进行通信,就必然要依赖于该协议的类库(SDK)进行编解码工作。既然如此,那么将协议的类库扩展,使其具有流量控制的能力,不就能代替 Sidecar 代理了吗?且 SDK 和应用同属于同一进程,必然有更优秀的性能表现,Sidecar 最为诟病的延迟问题也会迎刃而解。
2021 年 Istio 官方博客发表了一篇基于 gRPC 实现 Proxyless 的文章,详细阐述了其工作原理以及如何在 Istio 中使用它。如下图所示,在这种模式中,核心的流控能力被集成在 gRPC 库中,不再使用代理进行数据面通信。但它仍然需要一个 Agent 进行初始化并与控制平面交互,负责告知 gRPC 库如何连接到 istiod,如何获取证书,并作为 xDS 代理,代表应用与 istiod 进行连接和认证。
相比通过进程外通信的 Sidecar 代理来说,Proxyless 具有如下明显的优势:
性能:Proxyless 模式是进程内、点对点的直接通信,网络延迟比代理要小得多。
稳定性:SDK 类库与应用共享单一进程,拓扑结构简单,调试方便,消除了跨进程的调用,稳定性更高。
框架集成:对于传统的基于 SDK 实现的服务治理框架,如果集成了 Proxyless 模式,即能够复用框架现有的能力。
资源消耗低:无独立的 Sidecar 容器,内置类库资源消耗低。
从官方博客给出的数据来看,gRPC Proxyless 模式下的延迟情况接近基准测试,资源消耗也相对较低。
读者可能已经发现,所谓 Proxyless 其实和传统的 SDK 并无二致,只是将流控能力内嵌到负责通信协议的类库中,因此它具有和传统 SDK 服务框架相同的缺点:
语言绑定:需要开发多种语言的 SDK
侵入性:进程内类库,需编译到应用程序及侵入代码。
也正因为如此,业内很多人认为 Proxyless 本质上是一种倒退,是回归到传统的方式去解决服务通信的问题。笔者认为,软件设计的主要活动就是取舍,不存在一种完美的方案能解决所有问题。但不管怎样,服务网格领域的开发者们仍旧在探索和推动产品的演进,这才是我们最希望看到的结果。
如果说 Sidecar 是主流的服务网格架构形态的集大成者,围绕着 Sidecar 的夺位之争也在持续上演。既然有了去代理模式,那又何妨多个去边车模式?这就是所谓的 Sidecarless,也叫 Sidecar-free。2022 年 Cilium 基于 ebpf 技术发布了具有服务网格能力的产品。Cilium 的服务网格产品提供了两种模式,对于 L3/L4 层的能力直接由 ebpf 支持,L7 层能力由一个公共的代理负责,以 DaemonSet 方式部署。
Cilium 认为,内核加上共享型代理的引入可以极大的减少代理的数量,从而降低资源消耗和维护成本。而在内核层面进行通信管理也提高了性能。
但同样,软件领域没有银弹,Sidecarless 也是取舍后的结果。ebpf 并不是万能钥匙,也存在内核版本要求、编写难度大、安全等方面的问题。Linkerd 创始人 William Morgan 还总结了共享型代理存在的一些缺点:
资源管理不可评估:取决于集群中 Node 数量
隔离性:所有应用共用同一个代理,应用的稳定性可能会受到影响
爆炸半径变大:会影响整个 Node 节点的 Pod
安全问题更复杂:比如代理会保存整个 Node 节点的秘钥。
依笔者愚见,基于 ebpf 的服务网格在设计思路上其实和 Proxyless 如出一辙,即找到一个非 Sidecar 的地方去实现流量控制能力。它们一个是基于通信协议类库,一个是基于内核的扩展性。ebpf 通过内核层面提供的可扩展能力,在流量经过内核时实现了控制、安全和观察的能力,从而构建出一种新形态的服务网格。
2022 年 9 月 Istio 发布了一个名为“Ambient Mesh”的无边车数据平面模型,宣称用户可以弃用 Sidecar,以 Ambient Mesh 模式使用 Istio 的特性。Ambient Mesh 将 Istio 的功能分为两层,安全覆盖层用来处理 L4 层的路由和安全。如果需要,用户可以启用 L7 处理层从而使用更全面的功能特性。在这一点上它和 Cilium 的做法类似。
下图中 ztunnel 即为安全覆盖层,以 DaemonSet 部署,本质上是一个处理 L4 层场景的共享代理。图中的 Waypoint 代理以 Pod 形态部署于集群中,可使用 Istio 处理 L7 网络的完整能力。
我们可以将 Ambient Mesh 也看做是一种 Sidecarless 模式,但笔者更愿意将其称之为中心化代理模式,因为其核心思路是通过共享的、中心化的代理实现流量控制,从而代替应用容器旁的 Sidecar 代理。不过用户依然可以根据需要同时启用 Ambient Mesh 和 Sidecar,因为它们的关系是互补而不是互斥的。
从官方的博客来看,Istio 在过去的半年中一直在推进 Ambient Mesh 的开发,并于 2023 年 2 月将其合并到了 Istio 的主代码分支。这也从一定程度上说明 Istio 未来的发展方向之一就是持续的对 Ambient Mesh 改进并探索多种数据平面的可能性。
经过 6 年多的发展,服务网格已经迈进了早期主流(early majority)技术的行列。借助于新技术和新思路的不断涌现,架构形态也从最初的 Sidecar 模式变的更加多样化。我们现在很难定论谁会成为最终的胜利者,毕竟各个模式都存在优劣点,都有自己更适合的应用场景。也许服务网格也和程序设计语言一样,并不会出现统一的局面,而是在不断的自我完善中提供给用户更多的选择。
微信扫码关注该文公众号作者