From c42ba6884c3b0690e83223514a6a8927fd994bf0 Mon Sep 17 00:00:00 2001 From: isno Date: Thu, 30 Jan 2025 00:42:23 +0800 Subject: [PATCH] fix typo --- ServiceMesh/MicroService-history.md | 2 +- ServiceMesh/The-future-of-ServiceMesh.md | 55 ++++++----- ServiceMesh/conclusion.md | 2 +- ServiceMesh/control-plane.md | 20 ++-- ServiceMesh/data-plane.md | 116 +++++++---------------- ServiceMesh/overview.md | 10 +- 6 files changed, 79 insertions(+), 126 deletions(-) diff --git a/ServiceMesh/MicroService-history.md b/ServiceMesh/MicroService-history.md index 6fc26d5d..4be70068 100644 --- a/ServiceMesh/MicroService-history.md +++ b/ServiceMesh/MicroService-history.md @@ -104,7 +104,7 @@ Linkerd 开创先河的不绑定任何基础架构或某类技术体系,实现 第一代服务网格由一系列独立运行的代理型服务(Sidecar)构成,但并没有思考如何系统化管理这些代理服务。为了提供统一的运维入口,服务网格继续演化出了集中式的控制面板(Control Plane)。 -典型的第二代服务网格以 Google、IBM 和 Lyft 联合开发的 Istio 为代表。根据 Istio 的总体架构(见图 8-8),第二代服务网格由两大核心组成部分:一系列与微服务共同部署的边车代理,以及用于管理这些代理的控制器。代理间需要通信以转发程序间的数据包,而代理与控制器之间则通过通信传递路由、熔断策略、服务发现等控制信息。 +典型的第二代服务网格以 Google、IBM 和 Lyft 联合开发的 Istio 为代表。根据 Istio 的总体架构(见图 8-8),第二代服务网格由两大核心组成部分:一系列与微服务共同部署的边车代理(称为数据平面),以及用于管理这些代理的控制器(称为控制平面)。控制器向代理下发路由、熔断策略、服务发现等策略信息,代理根据这些策略处理服务间的请求。 :::center ![](../assets/6-b.png)
diff --git a/ServiceMesh/The-future-of-ServiceMesh.md b/ServiceMesh/The-future-of-ServiceMesh.md index 8fe3903c..5f32db85 100644 --- a/ServiceMesh/The-future-of-ServiceMesh.md +++ b/ServiceMesh/The-future-of-ServiceMesh.md @@ -1,26 +1,26 @@ # 8.6 服务网格的未来 -随着服务网格的逐步落地,Sidecar 模式的缺点也逐渐显现: +随着服务网格的逐步落地,边车代理的缺点也逐渐显现: -- **网络延迟问题**:服务网格通过 iptables 拦截服务间的请求,将原本的 A->B 通信改为 A->(iptables+Sidecar)-> (iptables+Sidecar)->B,调用链的增加导致了额外的性能损耗。尽管 Sidecar 的引入通常只会增加毫秒级(个位数)的延迟,但对于对性能要求极高的业务来说,额外的延迟是放弃服务网格的主要原因。。 -- **资源占用问题**:Sidecar 作为一个独立的容器必然占用一定的系统资源,对于超大规模集群(如有数万个 Pod)来说,巨大的基数使 Sidecar 占用资源总量变得相当可观。 +- **网络延迟问题**:服务网格通过 iptables 拦截服务间的请求,将原本的 A->B 通信改为 A->(iptables+Sidecar)-> (iptables+Sidecar)->B,调用链的增加导致了额外的性能损耗。尽管边车代理通常只会增加毫秒级(个位数)的延迟,但对性能要求极高的业务来说,额外的延迟是放弃服务网格的主要原因; +- **资源占用问题**:边车代理作为一个独立的容器必然占用一定的系统资源,对于超大规模集群(如有数万个 Pod)来说,巨大的基数使边车代理占用资源总量变得相当可观。 -为了解决上述问题,开发者们开始思考:“是否应该将服务网格与 Sidecar 划等号?”,并开始探索服务网格形态上的其他可能性。 +为了解决上述问题,开发者们开始思考:“是否应该将服务网格与边车代理划等号?”,并开始探索服务网格形态上的其他可能性。 ## 8.7.1 Proxyless 模式 既然问题出自代理,那就把代理去掉,这就是 Proxyless(无代理)模式。 -Proxyless 模式的设计思想是,服务间通信总依赖某种协议,那么将协议的实现(SDK)扩展,增加通信治理能力,不就能代替 Sidecar 了吗?且 SDK 和应用封装在一起,不仅有更优异的性能,还能彻底解决 Sidecar 引发的延迟问题。 +Proxyless 模式的思想是,服务间通信总依赖某种协议,那么将协议的实现(SDK)扩展,增加通信治理能力,不就能代替边车代理了吗?且 SDK 和应用封装在一起,不仅有更优异的性能,还能彻底解决边车代理引发的延迟问题。 -2021 年,Istio 发表文章《基于 gRPC 的无代理服务网格》[^1],介绍了一种基于 gRPC 实现的 Proxyless 模式的服务网格。它的工作原理如图 8-19 所示,服务间通信治理不再依赖 Sidecar,而是采用原始的方式在 gRPC SDK 中实现。此外,该模式额外需要一个代理(Istio Agent)与控制平面(Control Plane)交互,告知 gRPC SDK 如何连接到 istiod、如何获取证书、处理流量的策略等。 +2021 年,Istio 发表文章《基于 gRPC 的无代理服务网格》[^1],介绍了一种基于 gRPC 实现的 Proxyless 模式的服务网格。它的工作原理如图 8-19 所示,服务间通信治理不再依赖边车代理,而是采用原始的方式在 gRPC SDK 中实现。此外,该模式额外需要一个代理(Istio Agent)与控制平面(Control Plane)交互,告知 gRPC SDK 如何连接到 istiod、如何获取证书、处理流量的策略等。 :::center ![](../assets/proxyless.svg)
- 图 8-19 Proxyless 模式 + 图 8-19 Proxyless 模式的工作原理 ::: -相比 Sidecar,Proxyless 模式在性能、稳定性、资源消耗低等方面具有明显的优势。根据官方公布的性能测试报告来看,gRPC Proxyless 模式的延迟接近“基准”(baseline)、资源消耗也相对较低。 +相比边车代理模式,Proxyless 模式在性能、稳定性、资源消耗低等方面具有明显的优势。根据官方公布的性能测试报告来看,该模式的延迟接近“基准”(baseline)、资源消耗也相对较低。 :::center ![](../assets/latencies_p50.svg)
@@ -35,23 +35,25 @@ Proxyless 模式的设计思想是,服务间通信总依赖某种协议,那 2022 年 7 月,专注于容器网络领域的开源软件 Cilium 发布了 v1.12 版本。该版本最大的亮点是实现了一种无边车模式的服务网格。 -Cilium Sidecarless 模式的服务网格工作原理如图 8-21 所示。首先,Cilium 在节点中运行一个 Enovy 实例,作为所有容器的共享代理,这样每个 Pod 内就不需要放置一个 Sidecar 了。然后,借助 Cilium CNI 底层网络能力,当业务容器的数据包经过内核时,与节点中的共享代理打通,从而构建出一种全新形态的服务网格。 +Cilium 无边车模式的服务网格工作原理如图 8-21 所示。在这种模式下,Cilium 在节点中运行一个共享的 Envoy 实例,作为所有容器的代理,从而避免了每个 Pod 配置独立边车代理的需求。通过 Cilium CNI 提供的底层网络能力,当业务容器的数据包经过内核时,它们与节点中的共享代理进行连接,进而构建出一种全新的服务网格形态。 :::center ![](../assets/sidecarless.svg)
图 8-21 经过 eBPF 加速的服务网格和传统服务网格的区别 ::: -传统的服务网格 Linkerd、Istio 等几乎都是借助 Linux 内核网络协议栈处理请求,而 Cilium Sidecarless 模式基于 eBPF 技术在内核层面扩展,因此有着天然的网络加速效果。根据图 8-22 所示的性能测试来看,基于 eBPF 加速的 Envoy,比默认没有任何加速 Istio 要好很多。 +传统的服务网格,如 Linkerd 和 Istio,通常依赖 Linux 内核网络协议栈来处理请求,而 Cilium 的无边车模式则基于 eBPF 技术在内核层面进行扩展,从而实现了天然的网络加速效果。根据图 8-22 所示的性能测试结果,基于 eBPF 加速的 Envoy 在性能上显著优于默认未加速的 Istio。 :::center ![](../assets/cilium-istio-benchmark.webp)
图 8-22 Cilium Sidecarless 模式与 Istio Sidecar 模式的性能测试(结果越低越好) [图片来源](https://isovalent.com/blog/post/2022-05-03-servicemesh-security/) ::: -回过头看,Cilium Sidecarless 模式设计思路上其实和 Proxyless 如出一辙。即用一种非 Sidecar 的方式实现流量控制能力。两者的区别是: -- 一个基于通信协议类库; -- 另外一个基于共享代理,通过 eBPF 的 Linux 内核扩展技术实现。 + +回过头来看,Cilium Sidecarless 模式的设计思路与 Proxyless 模式非常相似,都是通过非边车代理的方式实现流量控制。两者的区别在于: + +- Proxyless 基于通信协议库; +- Cilium Sidecarless 则通过共享代理,利用 eBPF 技术在 Linux 内核层面实现。 但同样,软件领域没有银弹,eBPF 不是万能钥匙,它存在 Linux 内核版本要求高、代码编写难度大和容易造成系统安全隐患等问题。 @@ -59,35 +61,36 @@ Cilium Sidecarless 模式的服务网格工作原理如图 8-21 所示。首先 2022 年 9 月,服务网格 Istio 发布了一种全新的数据平面模式 “Ambient Mesh”[^2]。 -以往 Istio 的设计中,Sidecar 实现了从基本加密到高级 L7 策略所有数据平面功能。实践中,这使得 Sidecar 成为一个 0 和 1 的命题(要么全有,要么全无),即使服务对传输安全性要求不高,工程师们仍然需要付出部署和维护 Sidecar 的额外成本。 +在以往的 Istio 设计中,边车代理实现了从基本加密到高级 L7 策略的所有数据平面功能。这种设计使得边车代理成为一个“全有或全无”的方案,即使服务对传输安全性要求较低,工程师仍需承担部署和维护完整边车代理的额外成本。 -Ambient Mesh 的设计理念是:将数据平面分层,分为“安全覆盖层”(ztunnel)和七层处理层(waypoint 代理)。 +Ambient Mesh 的设计理念是,将数据平面分为“安全覆盖层”(ztunnel)和七层处理层(waypoint 代理)。 -四层用于基础处理,特点是低资源、高效率。它的功能包括: +安全覆盖层用于基础处理,特点是低资源、高效率。它的功能包括: -- 流量管理:TCP 路由 -- 安全:面向四层的简单授权策略、双向 TLS(即 mTLS) -- 可观测性:TCP 监控指标及日志 +- 流量管理:TCP 路由; +- 安全:面向四层的简单授权策略、双向 TLS(即 mTLS); +- 观测:TCP 监控指标及日志。 七层用于高级流量处理,特点是功能丰富(当然也需要更多的资源),它的功能包括: -- 流量管理: HTTP 路由、负载均衡、熔断、限流、故障容错、重试、超时等 -- 安全:面向七层的精细化授权策略 -- 可观测:HTTP 监控指标、访问日志、链路追踪 +- 流量管理: HTTP 路由、负载均衡、熔断、限流、故障容错、重试、超时等; +- 安全:面向七层的精细化授权策略; +- 观测:HTTP 监控指标、访问日志、链路追踪; + -在数据平面在分层解耦的模式下,安全覆盖层的能力下移至 CNI 组件中,ztunnel 在 Kubernetes 集群以 DaemonSet 的形式运行在每个节点中。这意味着,它为节点内所有的 Pod 提供服务的基础共享组件。 +在数据平面分层解耦的模式下,安全覆盖层的功能被转移至 ztunnel 组件,它以 DaemonSet 形式运行在 Kubernetes 集群的每个节点上。这意味着,ztunnel 是为节点内所有 Pod 提供服务的基础共享组件。 -另一方面,七层处理层不再以 Sidecar 模式存在,而是解耦出来,成为按需为命名空间创建的七层代理 Pod。Waypoint 组件在 Kubernetes 集群中以 Deployment 的形式部署,从 Kubernetes 的角度来看,Waypoint 只是个普通的 Pod,可以根据负载动态伸缩。业务 Pod 不再需要在 Sidecar 中运行代理才能参与网格,因此 Ambient 模式通常也被称为“无 Sidecar 网格”。 +另一方面,七层处理层不再以边车模式存在,而是按需为命名空间创建的 Waypoint 组件。Waypoint 组件以 Deployment 形式部署在 Kubernetes 集群中,从 Kubernetes 的角度来看,Waypoint 只是一个普通的 Pod,可以根据负载动态伸缩。业务 Pod 不再需要额外的边车容器即可参与网格,因此 Ambient 模式也被称为“无边车网格”。 :::center ![](../assets/Ambient-Mesh.svg)
- 图 8-23 Ambient-Mesh + 图 8-23 Ambient-Mesh 的工作原理 ::: Ambient 分层模式允许你以逐步递进的方式采用 Istio,你可以按需从无网格平滑过渡到安全的 L4 覆盖,再到完整的 L7 处理和策略。 根据 Istio 公开的信息,Istio 一直在推进 Ambient Mesh 的开发,并在 2023 年 2 月将其合并到了 Istio 的主分支。这个举措在一定程度上表明,Ambient Mesh 并非实验性质的“玩具”,而是 Istio 未来发展的重要方向之一 -无论是 Sidecarless 还是 Ambient Mesh,它们的设计思路本质是:用中心化的代理,替代位于应用容器旁边的 Sidecar 代理。这在一定程度上解决了传统 Sidecar 模式带来的资源消耗、网络延迟问题。但反面是,服务网格的设计理念本来就很抽象,引入 Proxyless、Sidecarless、Ambient Mesh 等模式,让原本抽象的设计更加难以理解。 +最后,无论是 Sidecarless 还是 Ambient Mesh,它们的设计本质上都是通过中心化代理替代位于应用容器旁边的代理容器。这在一定程度上解决了传统边车代理模式带来的资源消耗、网络延迟问题。但它们的缺陷也无法回避,服务网格的设计理念本来就很抽象,引入 Proxyless、Sidecarless、Ambient Mesh 等模式,进一步加大了服务网格的复杂性和理解难度。 [^1]: 参见 https://istio.io/latest/zh/blog/2021/proxyless-grpc/ [^2]: 参见 https://istio.io/latest/zh/blog/2023/ambient-merged-istio-main/ diff --git a/ServiceMesh/conclusion.md b/ServiceMesh/conclusion.md index 70fe0791..7a0b8cc2 100644 --- a/ServiceMesh/conclusion.md +++ b/ServiceMesh/conclusion.md @@ -1,6 +1,6 @@ # 8.7 小结 -在本章第二节,我们回顾了服务间通信的演变,并阐述了服务网格出现的背景。相信你已经理解,服务网格之所以受到青睐,关键不在于它提供了多少功能(这些功能传统 SDK 框架也有),而在于其将非业务逻辑从应用程序中剥离的设计思想。 +在本章第二节,我们回顾了服务间通信的演变,并阐述了服务网格出现的背景。相信你已经理解,服务网格之所以备受推崇,关键不在于它提供了多少功能(这些功能传统 SDK 框架也有),而在于其将非业务逻辑从应用程序中剥离的设计思想。 从最初 TCP/IP 协议的出现,我们看到网络传输相关的逻辑从应用层剥离,下沉至操作系统,成为操作系统的网络层。分布式系统的崛起,又带来了特有的分布式通信语义(服务发现、负载均衡、限流、熔断、加密...)。为了降低治理分布式通信的心智负担,面向微服务的 SDK 框架出现了,但这类框架与业务逻辑耦合在一起,带来门槛高、无法跨语言、升级困难三个固有问题。 diff --git a/ServiceMesh/control-plane.md b/ServiceMesh/control-plane.md index e9b1e8df..c09a1dce 100644 --- a/ServiceMesh/control-plane.md +++ b/ServiceMesh/control-plane.md @@ -4,7 +4,7 @@ Istio 自发布首个版本以来,有着一套“堪称优雅”的架构设计,它的架构由数据面和控制面两部分组成,前者通过代理组件 Envoy 负责流量处理;后者根据功能职责不同,由多个微服务(如 Pilot、Galley、Citadel、Mixer)组成。 Istio 控制面组件的拆分设计看似充分体现了微服务架构的优点,如职责分离、独立部署和伸缩能力,但在实际场景中,并未实现预期的效果。 -:::tip 服务网格控制面的问题 +:::tip Isito 控制平面的问题 当业务调用出现异常时,由于接入了服务网格,工程师首先需要排查控制面内各个组件的健康状态:首先检查 Pilot 是否正常工作,配置是否正确下发至 Sidecar;然后检查 Galley 是否正常同步服务实例信息;同时,还需要确认 Sidecar 是否成功注入。 一方面,控制面组件的数量越多,排查问题时需要检查的故障点也就越多。另一方面,过多的组件设计也会增加部署、维护的复杂性。 @@ -12,24 +12,24 @@ Istio 自发布首个版本以来,有着一套“堪称优雅”的架构设 服务网格被誉为下一代微服务架构,用来解决微服务间的运维管理问题。但在服务网格的设计过程中,又引入了一套新的微服务架构。这岂不是“用一种微服务架构设计的系统来解决另一种微服务架构的治理问题”?那么,谁来解决 Istio 系统本身的微服务架构问题呢? -在 Istio 推出三年后,即 Istio 1.5 版本,开发团队对控制面架构进行了重大调整,摒弃了之前的设计,转而采用了“复古”的单体架构。新的统一组件 istiod 整合了 Pilot、Citadel 和 Galley 的功能,并以单个二进制文件的形式进行部署,承担起之前各个组件的所有职责: +在 Istio 推出三年后,即 Istio 1.5 版本,开发团队对控制面架构进行了重大调整,摒弃了之前的设计,转而采用了“复古”的单体架构。组件 istiod 整合了 Pilot、Citadel 和 Galley 的功能,以单个二进制文件的形式部署,承担起之前组件的所有职责: -- **服务发现与配置分发**:从 Kubernetes 等平台获取服务信息,将路由规则和策略转换为 xDS 协议下发至 Envoy 代理。 -- **流量管理**:管理流量路由规则,包括负载均衡、分流、镜像、熔断、超时与重试等功能。 -- **安全管理**:生成、分发和轮换服务间的身份认证证书,确保双向 TLS 加密通信;基于角色的访问控制(RBAC)和细粒度的授权策略,限制服务间的访问权限。 -- **可观测性支持**:协助 Envoy 采集运行时指标(如延迟、错误率、请求流量等),并将数据发送到外部监控系统(如 Prometheus);支持分布式追踪系统(如 Jaeger、Zipkin 和 OpenTelemetry),帮助分析跨服务调用链路;提供访问日志和事件日志的采集功能。 -- **配置验证与管理**:验证用户提交的网格配置,并将其分发到数据平面,确保一致性和正确性。 +- **服务发现与配置分发**:从 Kubernetes 等平台获取服务信息,将路由规则和策略转换为 xDS 协议下发至 Envoy 代理; +- **流量管理**:管理流量路由规则,包括负载均衡、分流、镜像、熔断、超时与重试等功能; +- **安全管理**:生成、分发和轮换服务间的身份认证证书,确保双向 TLS 加密通信、基于角色的访问控制(RBAC)和细粒度的授权策略,限制服务间的访问权限; +- **可观测性支持**:协助 Envoy 采集系统输出的遥测数据(日志、指标、追踪),并将数据发送到外部监控系统(如 Prometheus、Jaeger、OpenTelemetry 等); +- **配置验证与管理**:验证用户提交的网格配置,并将其分发到数据平面,确保一致性和正确性; :::center ![](../assets/service-mesh-arc.svg)
图 8-12 Istio 架构及各个组件 ::: -Istio 1.5 版本的架构变化,实际上是将原有的多进程设计转换为单进程模式,以最小的成本实现最高的运维收益。 +Istio 1.5 版本的架构变化,实际上是将原有的多进程设计转换为单进程模式,以最小的成本实现最高的运维收益: - 运维配置变得更加简单,用户只需要部署或升级一个单独的服务组件; - 更加容易排查错误,因为不需要再横跨多个组件去排查各种错误; - 更加利于做灰度发布,因为是单一组件,可以非常灵活切换至不同的控制面; -- 避免了组件间的网络开销,因为组件内部可直接共享缓存、配置等,也会降低资源开销; +- 避免了组件间的网络开销,因为组件内部可直接共享缓存、配置等,也会降低资源开销。 -通过以上分析,你是否对 Istio 控制平面的拆分架构有了新的理解?看似优雅的架构设计,落地过程中往往给运维和开发人员带来意料之外的困难。正如一句老话,没有完美的架构,只有最合适的架构! \ No newline at end of file +通过以上分析,你是否对 Istio 控制平面的拆分架构有了新的理解?看似优雅的架构设计,落地过程中往往给工程师带来意料之外的困难。正如一句老话,没有完美的架构,只有最合适的架构! \ No newline at end of file diff --git a/ServiceMesh/data-plane.md b/ServiceMesh/data-plane.md index bc205b25..ad4f0d81 100644 --- a/ServiceMesh/data-plane.md +++ b/ServiceMesh/data-plane.md @@ -1,26 +1,22 @@ # 8.3 数据平面的设计 -数据平面由轻量级的网络代理(如 Envoy 或 Linkerd Proxy)组成,核心职责是在不可靠的网络环境中确保服务间通信的可靠性。确保服务间通信的可靠性并不是什么高深的技术,业内追捧服务网格原因在于,实现上述目标的整个过程无需手动配置,对应用完全透明。 - -接下来,笔者将从 Sidecar 自动注入、流量透明劫持、实现可靠通信三个方面展开讨论数据平面的设计原理。 +服务间通信治理并非复杂的技术,服务网格之所以备受追捧,正是因为它能够自动化实现这一过程,且对应用完全透明。接下来,笔者将从边车代理(Sidecar)自动注入、请求透明劫持和可靠通信实现三个方面,探讨数据平面的设计原理。 ## 8.3.1 Sidecar 自动注入 -只要用过 Istio 的读者一定知道,带有 istio-injection: enabled 标签的命名空间中创建 Pod,Kubernetes 会自动为创建的 Pod 注入一个名为 istio-proxy 的 Sidecar 容器。 - -实现自动注入 Sidecar 的核心在于 Kubernetes 的准入控制器。 +使用过 Istio 的读者一定知道,在带有 istio-injection: enabled 标签的命名空间中创建 Pod 时,Kubernetes 会自动为其注入一个名为 istio-proxy 的边车容器。这套机制的核心在于 Kubernetes 的准入控制器。 -:::tip 准入控制器 -准入控制器会拦截 Kubernetes API Server 收到的请求,在资源对象被持久化到 etcd 之前,对这些对象进行校验和修改。准入控制器分为两类:Mutating 和 Validating: -- Validating 类型的准入控制器用于校验请求,它们不能修改对象,但是可以拒绝不符合特定策略的请求; -- Mutating 类型的准入控制器在对象被创建或更新时可以修改它们。 +:::tip Kubernetes 准入控制器 +Kubernetes 准入控制器会拦截 Kubernetes API Server 接收到的请求,在资源对象被持久化到 etcd 之前,对其进行校验和修改。准入控制器分为两类: +- **Validating** 类型准入控制器:用于校验请求,无法修改对象,但可以拒绝不符合特定策略的请求; +- **Mutating** 类型准入控制器:在对象创建或更新时,可以修改资源对象。 ::: Istio 预先在 Kubernetes 集群中注册了一个类型为 Mutating 类型的准入控制器,它包含以下内容: -- Webhook 服务地址:指向运行注入逻辑的 Webhook 服务(如 Istio 的 istio-sidecar-injector)。 -- 匹配规则:定义哪些资源和操作会触发此 Webhook,例如针对 Pod 的创建请求。 -- 注入条件:通过 Label 或 Annotation 决定是否对某些 Pod 进行注入。 +- Webhook 服务地址:指向运行注入逻辑的 Webhook 服务,例如 Istio 的 istio-sidecar-injector; +- 匹配规则:定义哪些资源和操作会触发该 Webhook,比如针对 Pod 创建请求(operations: ["CREATE"]); +- 注入条件:通过 Label(istio-injection: enabled) 或 Annotation 决定是否注入某些 Pod。 ```yaml apiVersion: admissionregistration.k8s.io/v1 @@ -45,12 +41,9 @@ webhooks: istio-injection: enabled ``` -以上配置指示 Kubernetes 在带有 istio-injection: enabled 标签的命名空间中,拦截 Pod 创建请求并触发 Istio 的 Webhook。Webhook 服务会将 Sidecar 容器(如 Envoy)注入到 Pod 配置中。之后,Kubernetes 使用更新后的配置完成资源调度和 Pod 创建流程。 - - ## 8.3.2 流量透明劫持 -Isito 在注入边车代理后,还会注入一个初始化容器 istio-init。该容器的配置如下: +Isito 通过准入控制器,还会注入一个初始化容器 istio-init,该容器的配置如下: ```yaml initContainers: @@ -58,9 +51,9 @@ initContainers: image: docker.io/istio/proxyv2:1.13.1 args: ["istio-iptables", "-p", "15001", "-z", "15006", "-u", "1337", "-m", "REDIRECT", "-i", "*", "-x", "", "-b", "*", "-d", "15090,15021,15020"] ``` -上述配置中,istio-init 容器的入口命令是 istio-iptables,该命令设置一系列 iptables 规则,对除了特定的几个端口,如 15090、15021、15020 的流量拦截,重定向到 Istio 的 Sidecar 代理(Envoy)上: -- 对于入站流量,它会将流量重定向到 Sidecar 代理监听的端口(通常是 15006 端口); -- 对于出站流量,它会将流量重定向到 Sidecar 代理监听的另一个端口(通常是 15001 端口)。 +在上述配置中,istio-init 容器的入口命令为 istio-iptables,该命令配置了一系列 iptables 规则,用于拦截并重定向除特定端口(如 15090、15021、15020)外的流量到 Istio 的边车代理(Envoy): +- 对于入站(Inbound)流量,会被重定向到边车代理监听的端口(通常为 15006)。 +- 对于出站(Outbound)流量,则会被重定向到边车代理监听的另一个端口(通常为 15001)。 通过 iptables -t nat -L -v 命令查看 istio-iptables 添加的 iptables 规则。 @@ -110,26 +103,26 @@ Chain ISTIO_REDIRECT (2 references) 53 3180 REDIRECT tcp -- any any anywhere anywhere redir ports 15001 ``` -根据图 8-10 进一步理解上述 iptables 自定义链(以 ISTIO_开头)处理流量的逻辑, +根据图 8-10 进一步理解上述 iptables 自定义链(以 ISTIO_开头)处理流量的逻辑。 :::center ![](../assets/istio-iptables.svg)
图 8-10 Istio 透明流量劫持示意图 ::: - -使用 iptables 实现流量劫持是最经典的方式。不过,客户端 Pod 到服务端 Pod 之间的网络数据路径,至少要来回进入 TCP/IP 堆栈 3 次(出站、客户端 Sidecar Proxy 到服务端 Sidecar Proxy、入站)。如何降低流量劫持的延迟和资源消耗,是服务网格未来的主要研究方向。在 8.5 节,笔者将介绍 Proxyless 模式、Sidecarless 模式、Ambient Mesh 模式。 +使用 iptables 实现流量劫持是最经典的方式。不过,客户端 Pod 和服务端 Pod 之间的网络数据路径需要至少经过三次 TCP/IP 堆栈(出站、客户端边车代理到服务端的边车代理、入站)。如何降低流量劫持的延迟和资源消耗,是服务网格未来的主要研究方向,笔者将在 8.5 节探讨这一问题。 ## 8.3.3 实现可靠通信 -通过 iptables 劫持流量,转发至 Sidecar 后,Sidecar 根据配置接管应用程序之间的通信。 - -传统的代理(如 HAProxy 或者 Nginx)依赖静态配置文件来定义各种资源以及数据转发规则。而 Envoy 几乎所有配置都可以通过订阅来动态获取。 +通过 iptables 劫持流量,转发至边车代理后,边车代理根据配置接管应用程序之间的通信。 -Envoy 将代理转发行为所涉及的配置抽象为三类资源:Listener、Cluster、Router。并以此为基础,定义了一系列标准数据面 API 用来发现和操作这些资源。 +传统的代理(如 HAProxy 或 Nginx)依赖静态配置文件来定义资源和数据转发规则,而 Envoy 则几乎所有配置都可以动态获取。Envoy 将代理转发行为的配置抽象为三类资源:Listener、Cluster 和 Router,并基于这些资源定义了一系列标准数据面 API,用于发现和操作这些资源。这套标准数据面 API 被称为 xDS。 -这套标准数据面 API 叫 xDS。xDS 是指 "X Discovery Service",这里的 "X" 代指多种服务发现协议。 +xDS 的全称是 "x Discovery Service",这里的 "x" 代指表 8-1 中的协议族。 +:::center +表 9-1 xDS v3.0 协议族 +::: | 简写 | 全称 | 描述 | | :--: | :--------------------------------: | :----------------: | | LDS | Listener Discovery Service | 监听器发现服务 | @@ -147,67 +140,24 @@ Envoy 将代理转发行为所涉及的配置抽象为三类资源:Listener、 | ECDS | Extension Config Discovery Service | 扩展配置发现服务 | | xDS | X Discovery Service | 以上诸多API的统称 | -具体到每个 xDS 协议都包含大量的内容,笔者不再详述。但通过这些协议操作的资源,可大致说清楚它们的工作原理。 +具体到每个 xDS 协议都包含大量的内容,笔者无法一一详述。但通过这些协议操作的资源,再结合图 8-11,可大致说清楚它们的工作原理。 -- **Listener**:Listener 可以理解为 Envoy 打开的一个监听端口,用于接收来自 Downstream(下游服务,即客户端)连接。每个 Listener 配置中核心包括监听地址、Filter 链(filter_chains)等。Envoy 支持多个 Listener,不同 Listener 之间几乎所有的配置都是隔离的。 - - Listener 对应发现服务称之为 LDS(Listener Discovery Service)。LDS 是 Envoy 正常工作的基础,没有 LDS,Envoy 就不能实现端口监听,其他所有 xDS 服务也失去了作用。 -- **Cluster**:在 Envoy 中,每个 Upstream(上游服务,即业务后端)被抽象成一个 Cluster。Cluster 包含该服务的连接池、超时时间端口、类型等等。上游服务即处理业务的后端,具体到 Kubernetes 中,则对应到某个 Service 服务。 - - Cluster 对应的发现服务称之为 CDS(Cluster Discovery Service)。一般情况下,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(Route Discovery Service)。Router 中最核心配置包含匹配规则和目标 Cluster。此外,也可能包含重试、分流、限流等等。 -Envoy 的另一项重要设计是其可扩展的 Filter 机制,通俗地讲就是 Envoy 的插件系统。Envoy 的许多核心功能都基于 Filter 实现,例如,针对 HTTP 流量和服务的治理主要依赖于两个插件:HttpConnectionManager(网络 Filter,负责协议解析)和 Router(负责流量分发)。通过 Filter 机制,Envoy 理论上能够支持任意协议,实现协议间的转换,并对请求流量进行全面的修改和定制。 - -Filter 并没有独立的 xDS 服务来进行配置发现,其所有配置都嵌套在其他 xDS 服务中,例如 LDS(Listener Discovery Service)、RDS(Route Discovery Service)和 CDS(Cluster Discovery Service)等 +- **Listener**:Listener 可以理解为 Envoy 打开的一个监听端口,用于接收来自 Downstream(下游服务,即客户端)连接。每个 Listener 配置中核心包括监听地址、插件(Filter)等。Envoy 支持多个 Listener,不同 Listener 之间几乎所有的配置都是隔离的。 + + Listener 对应发现服务称之为 LDS。LDS 是 Envoy 正常工作的基础,没有 LDS,Envoy 就不能实现端口监听,其他所有 xDS 服务也失去了作用。 +- **Cluster**:在 Envoy 中,每个 Upstream(上游服务,即业务后端,具体到 Kubernetes,则对应某个 Service)被抽象成一个 Cluster。Cluster 包含该服务的连接池、超时时间端口、类型等等。 + 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。此外,也可能包含重试、分流、限流等等。 :::center ![](../assets/envoy-resource.png)
- 图 8-11 Envoy 的动态配置示例 - + 图 8-11 Envoy 的工作原理 ::: -最后,笔者用一个静态配置例子说明上述资源工作原理: - -```yaml -static_resources: - listeners: - - name: listener_0 - address: - socket_address: { address: 0.0.0.0, port_value: 8080 } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - config: - route_config: - name: local_route - virtual_hosts: - - name: backend - domains: ["*"] - routes: - - match: { prefix: "/service1" } - route: { cluster: service1_cluster } - - match: { prefix: "/service2" } - route: { cluster: service2_cluster } - http_filters: - - name: envoy.filters.http.router - - clusters: - - name: service1_cluster - connect_timeout: 0.25s - type: STRICT_DNS - lb_policy: ROUND_ROBIN - load_assignment: - cluster_name: service_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: { address: service1.example.com, port_value: 80 } - - name: service2_cluster - ... -``` +Envoy 的另一项重要设计是其可扩展的 Filter 机制,通俗地讲就是 Envoy 的插件系统。 -当客户端发送一个请求到 `http://:8080/service1` 时,Envoy 的 Listener 将接收该请求,使用路由规则将其转发到 service1_cluster。类似地,`http://:8080/service2` 的请求将被转发到 service2_cluster。 \ No newline at end of file +Envoy 的插件机制允许开发者通过基于 xDS 的数据流管道,插入自定义逻辑,从而扩展和定制 Envoy 的功能。Envoy 的很多核心功能是通过 Filter 实现的。例如,HTTP 流量的处理和服务治理依赖于两个关键插件 HttpConnectionManager(网络 Filter,负责协议解析)和 Router(负责流量分发)。通过 Filter 机制,Envoy 理论上能够支持任意协议,并对请求流量进行全面的修改和定制。 \ No newline at end of file diff --git a/ServiceMesh/overview.md b/ServiceMesh/overview.md index b1069ceb..72d1a13b 100644 --- a/ServiceMesh/overview.md +++ b/ServiceMesh/overview.md @@ -2,8 +2,8 @@ 2016 年,Buoyant 公司发布了 Linkerd。Matt Klein 离开 Twitter 并加入 Lyft,启动了 Envoy 项目。第一代服务网格稳步发展时,世界另一角落,Google 和 IBM 两个巨头联手,与 Lyft 一起启动了第二代服务网格 Istio。 -- 以 Linkerd 为代表的第一代服务网格,通过 Sidecar 控制微服务间的流量; -- 以 Istio 为代表的第二代服务网格,新增控制平面,管理了所有 Sidecar。于是,Istio 对微服务系统掌握了前所未有的控制力。 +- 以 Linkerd 为代表的第一代服务网格,通过边车代理控制微服务间的流量; +- 以 Istio 为代表的第二代服务网格,新增控制平面,管理了所有边车代理。于是,Istio 对微服务系统掌握了前所未有的控制力。 依托行业巨头的背书与创新的控制平面设计理念,让 Istio 得到极大关注和发展,并迅速成为业界落地服务网格的主流选择。 @@ -14,7 +14,7 @@ Buoyant 公司的第二代服务网格使用 Rust 构建数据平面 linkerd2-proxy ,使用 Go 开发了控制平面 Conduit,主打轻量化,目标是世界上最轻、最简单、最安全的 Kubernetes 专用服务网格。该产品最初以 Conduit 命名,Conduit 加入 CNCF 后不久,宣布与原有的 Linkerd 项目合并,被重新命名为 Linkerd 2[^1]。 Linkerd2 的架构如图 8-13 所示,增加了控制平面,但整体相对简单: -- 控制层面组件只有 destination(类似 Istio 中的 Pilot 组件)、identity(类似 Istio 中的 Citadel)和 proxy injector(代理注入器)。 +- 控制层面组件只有 destination(类似 Istio 中的 Pilot 组件)、identity(类似 Istio 中的 Citadel)和 proxy injector(代理注入器); - 数据平面中 linkerd-init 设置 iptables 规则拦截 Pod 中的 TCP 连接,linkerd-proxy 实现对所有的流量管控(负载均衡、熔断..)。 :::center @@ -43,14 +43,14 @@ Linkerd2 的架构如图 8-13 所示,增加了控制平面,但整体相对 两年之后,Linkerd 与 Istio 都发布了多个更成熟的版本,两者的性能表现如何?笔者引用 William Morgan 文章《Benchmarking Linkerd and Istio》[^3]中的数据,向读者介绍 Linkerd v2.11.1、Istio v1.12.0 两个项目之间延迟与资源消耗的表现。 -首先是网络延迟层面的对比。如图 8-15 所示,中位数(P50)延迟的表现上,Linkerd 在 6ms 的基准延迟上增加了 6ms 额外延迟,而 Istio 的额外延迟为 15ms。值得注意的是,P90 以后两者出现明显差异,最极端的 Max 数据表现上,Linkerd 在 25ms 的基准延迟上增加了 25 ms 额外延迟,而 Istio 则增大了 5 倍,高达 253 ms 额外延迟。 +首先是网络延迟的对比。如图 8-15 所示,在中位数(P50)延迟上,Linkerd 在 6ms 的基准延迟基础上增加了 6ms,而 Istio 增加了 15ms。值得注意的是,从 P90 开始,两者的差异明显扩大。在最极端的 Max 数据上,Linkerd 在 25ms 的基准延迟上增加了 25ms,而 Istio 则增加了 5 倍,达到 253ms 的额外延迟。 :::center ![](../assets/latency-200rps.png)
图 8-15 Linkerd 与 Istio 的延迟对比 ::: -接着是资源消耗层面的对比。如图 8-16 所示,Linkerd 代理消耗的内存最大 26 Mb,Istio 的 Envoy 代理消耗的内存最大 156.2 Mb,是 Linkerd 的 6倍。同样,Linkerd 的最大代理 CPU 时间记录为 36ms,而 Istio 的代理 CPU 时间记录为 67ms,比前者多出 85%。 +接下来是资源消耗的对比。如图 8-16 所示,Linkerd 代理的最大内存消耗为 26MB,而 Istio 的 Envoy 代理则为 156.2MB,是 Linkerd 的 6 倍。此外,Linkerd 的最大代理 CPU 时间为 36ms,而 Istio 的代理 CPU 时间为 67ms,比前者多出 85%。 :::center ![](../assets/linkerd-resource.png)