Linkerd,其实也很 Diao 的

2021-12-09 21:06:02 浏览数 (1)

在之前的文章,我们介绍了有关 Service Mesh (服务网格)微服务生态体系中的 2个核心成员 Linkerd 和 Istio ,具体可参考相关链接:微服务之 Service Mesh浅析 以及 Service Mesh 体系解析。对于2者,其都是围绕“ Control Plane (控制平面)” 和“ Date Plane (数据平面)” 展开。其中,Control Plane (控制平面)可以为路由流量管理和配置代理,并配置 Mixer 来强制执行策略并收集遥测数据。而对于 Date Plane (数据平面)而言,其是一组作为 Sidecar 部署的智能代理。这些代理会接收并控制服务网格内不同微服务之间的所有入站和出站网络数据。

对于 Istio 而言,其使用基于 Envoy 代理的扩展版本,Envoy 是以 C 开发的高性能代理,用于调解服务网格中所有服务的所有入站和出站流量。作为已经很成熟的 Envoy 代理,其是由 lyft 开源的边缘和服务代理,后被捐赠给CNCF基金会。可以说,Envoy 已经是云原生时代数据平面的事实标准。新兴 API 网关如 Gloo, Ambassador 都基于 Envoy 进行扩展开发;而在服务网格中,Istio、Kong 社区 Kuma、亚马逊AWS App Mesh 都使用 Envoy 作为默认数据面。而 Linkerd 使用专门为服务网格构建的 Rust “微代理”,简称为 Linkerd-Proxy 。那么问题来了,Linkerd 所采用的 Linkerd-Proxy 到底有多香?这也是本文所探讨的内容。

在讲解之前,我们先了解一下 Envoy 的相关概念及基础原理。在 Envoy 中,数据请求的入口方向被定义为下游(Downstream),而数据请求的出口方向则定义为上游(Upstream)。在通常情况下,Envoy 接收来自下游的请求并将之转发给上游。在下游方向,Envoy 使用监听器(Listener)来监听数据端口,接受下游连接和请求;而在上游方向,Envoy 则使用集群(Cluster)来抽象上游服务,管理连接池以及与之相关的健康检查等配置。同时,在监听器和集群之间,Envoy 则使用筛选器(Filter)和路由(Router)将两者联系在一起。相比于监听器、集群和路由等概念,筛选器可能需要稍微再多一点解释。筛选器是 Envoy 中可拔插的多种功能组件的统称,简单来说,筛选器就是插件。其架构示意图,具体如下所示:

基于上述架构示意图, Envoy 最为核心的组件主要体现在监听器(Listener)、集群(Cluster)、路由(Router)以及筛选器 (Filter)等4部分。接下来,我们对核心组件进行简要的解析,具体如下:

Listener

作为 Envoy 工作的基础部件,其简单理解为,Listener 是 Envoy 打开的一个监听端口,用于接收来自 Downstream(客户端)连接。Envoy 可以支持复数个 Listener。多个 Listener 之间几乎所有的配置都是隔离的。Listener 配置中核心包括监听地址、Filter 链等。

Listener 对应的配置/资源发现服务称之为 LDS。LDS 是 Envoy 正常工作的基础,没有 LDS,Envoy 就不能实现端口监听(如果启动配置也没有提供静态 Listener 的话),其他所有 xDS 服务也失去了作用。

Cluster

此部件即为对上游服务的抽象。在 Envoy 中,每个 Upstream 上游服务都被抽象成一个 Cluster。Cluster 包含该服务的连接池、超时时间、Endpoints地址、端口、类型(类型决定了 Envoy 获取该 Cluster 具体可以访问的 Endpoint方法)等等。

Cluster 对应的配置/资源发现服务称之为 CDS。一般情况下,CDS 服务会将其发现的所有可访问服务全量推送给 Envoy。与 CDS 紧密相关的另一种服务称之为 EDS。CDS服务负责 Cluster 资源的推送。而当该 Cluster 类型为 EDS 时,说明该 Cluster 的所有 Endpoints 需要由 xDS 服务下发,而不使用 DNS 等去解析。下发 Endpoints 的服务就称之为 EDS。

Router

此部件主要作为上下游之间的桥梁。Listener 可以接收来自下游的连接,Cluster 可以将流量发送给具体的上游服务,而 Router 则决定 Listener 在接收到下游连接和数据之后,应该将数据交给哪一个 Cluster 处理。它定义了数据分发的规则。虽然说到 Router 大部分时候都可以默认理解为 HTTP 路由,但是 Envoy 支持多种协议,如 Dubbo、Redis 等,所以此处 Router 泛指所有用于桥接 Listener 和后端服务(不限定HTTP)的规则与资源集合。

Route对应的配置/资源发现服务称之为 RDS。Router 中最核心配置包含匹配规则和目标 Cluster,此外,也可能包含重试、分流、限流等等。

Filter

Filter,通俗的讲,就是插件。通过 Filter 机制,Envoy 提供了极为强大的可扩展能力。在 Envoy 中,很多核心功能都使用 Filter 来实现。比如对于 Http 流量和服务的治理就是依赖 HttpConnectionManager(Network Filter,负责协议解析)以及 Router(负责流量分发)两个插件来实现。利用 Filter 机制,Envoy 理论上可以实现任意协议的支持以及协议之间的转换,可以对请求流量进行全方位的修改和定制。强大的 Filter 机制带来的不仅仅是强大的可扩展性,同时还有优秀的可维护性。Filter 机制让 Envoy 的使用者可以在不侵入社区源码的基础上对Envoy做各个方面的增强。

Filter 本身并没有专门的 xDS 服务来发现配置。Filter 所有配置都是嵌入在 LDS、RDS 以及 CDS(Cluster Network Filter)中的。

接下来,我们在了解一下 Envoy 的 2 种角色场景,具体如下图所示:

(此图源自官网)

作为一个服务代理组件,Envoy 并不限定自己的使用方法。它最常扮演的是两种不同的角色,一种是作为集群流量入口 API 网关(Gateway),管理南北向流量;另一种则是作为服务 Sidecar,拦截并治理 Service Mesh(服务网格)中东西向流量。

API 网关负责集中管理集群或者网格对外暴露的接口,为集群外或者网格外客户端调用集群内或网格内服务提供了统一的流量入口和治理方案,其重要性在整个微服务体系中自然不必多言。

Sidecar 是当前微服务领域先进的实践。微服务框架解决了单体应用过于复杂、难以维护、语言绑定以及不易扩展等问题,使得多种语言、多种框架的多个微服务构成一个整体,并通过 API 网关向外提供统一接口。但与此同时,微服务框架也带来了服务治理复杂、故障定位难、服务注册、服务发现等新挑战。

上述为基于 Envoy 的相关基础概念及架构解析,在实际的应用场景中,其真的是完美无瑕,不可挑剔吗?William Morgan 给出了自己的答案。

Linkerd 不使用 Envoy,因为 Envoy 不允许我们构建世界上最轻量、最简单、最安全的 Kubernetes 服务网格。

因为,成为最轻量、最简单、最安全的 Kubernetes 服务网格是 Linkeder 对用户的承诺,这也是 Linkerd 在服务网格中的独特之处:简单、更轻、更安全。我们之所以能够做到这一点,是因为我们构建的是 Linked2 代理,而不是 Envoy。不是因为 Envoy 不好,而是因为 Linkerd2 代理更好——至少,对于 Kubernetes Sidecar 代理这个非常具体和有限的用例来说。具体如下:

相对于 Envoy ,Linkerd2 代理是一个“微型代理”,专门为服务 Mesh Sidecar用例设计。Linkerd2 Proxy 是建立在2020年左右世界上最现代的网络编程环境(Rust Asynchronous Network Ecosystem,包括 Tokio、Tower 和 Hyper 等库)的基础上的,并推动了该环境的许多需求。就纯粹的技术进步而言,Linkerd2 Proxy是整个CNCF领域中最先进的技术之一。

与 Envoy 一样,Linkerd2 Pproxy 是一个100%开源的 Apachev2 CNCF 项目,它的特点是定期进行第三方审核、活跃的社区以及在世界各地的任务关键型系统中的大规模生产使用。与 Envoy 不同,Linkerd2 代理只针对一种用例设计:在从 Linkerd 控制平面接收配置的同时,向单个 Kubernetes Pod 发送代理请求。与 Envoy 不同的是,Linkerd2 Proxy 被设计成一个实现细节:它不是面向用户的,不能用作通用的构建块,而且它有一个乏味的名字。这意味着 Linkerd2 Proxy 往往不被注意,尽管我们最近试图通过一些文章对其进行更深入的了解。

1、复杂性

Envoy 是一个灵活的通用代理,这也是它受欢迎的主要原因。你可以使用特使作为入口,作为出口,作为服务 Sidecar,并在许多其他方面。但这种灵活性同时带来了复杂性。

作为比较点,截至2020年11月,Envoy RIPO 以172 kLc的 C 代码衡量,具有19K的3的“复杂性分数”(以分支和循环来衡量)。相反,Linkerd2 代理在30 kLoc中出现,并且具有1.5 K的复杂性分数。换句话说:Linkerd2 代理库比 Envoy 小5倍,其复杂性不言而喻。

2、资源消耗

对于任何基于 Sidecar 的服务网格,有一点是清楚的:将拥有许多代理。这意味着数据平面消耗的聚合 CPU 和内存是运行服务网格成本的一个关键组成部分,尤其是随着应用程序的扩展。使用Linkerd2 代理可以让我们严格控制 Linkerd 的资源消耗。在我们使用 Kinvolk 的开放源代码基准测试工具对 Linkerd 和 Istio 进行的内部基准测试中,例如,在4000 rpm(每秒请求数)的入口流量下,我们看到 Linkerd2 代理实例的内存始终在14mb到15mb之间,而 Istio 的 Envoy 则在135mb到175mb之间,是其大小的十倍。类似地,Linkerd2 代理在测试运行中的 CPU 使用率始终是每个实例15毫秒(CPU毫秒),而 Istio 的 Envoy 则从22毫秒到156毫秒不等,多了50%到10倍。也就是说,在实际的 Service Mesh 上下文中,Linkerd2 代理使用的系统资源只相当于 Envoy 使用的一小部分。

3、安全性

数据平面的安全性是任何服务网格都非常关心的问题。我们选择对 Linkerd2 代理是有初衷的:Rust 的内存安全性允许我们自信地在 Linkerd2 代理中编写安全代码,从而最大限度地减少了我们对人类捕获问题的依赖。当然,这不是说 Linkerd2 代理不能有安全漏洞!相反,它将更少;我们将需要少依赖自己的谦逊才能来避免这些天赋;我们将不太经常地强加给我们的用户,以升级他们的系统,以保持安全。而基于 C 代码很难保证,即使是最有经验的程序员也是如此,因为修复它,过于昂贵,困难,而且容易失败。

最后,Linkerd 可以使用 Envoy 吗?或者取代 Envoy 吗?大家有兴趣的话,可以随时留言交流,至此,本文的相关解析到此为止。

0 人点赞