一、服务治理
① “服务治理”简介
在微服务时代,一个复杂的应用程序被分解为多个组件化、协作和连接的单元,服务往往会承担越来越多的业务责任,这使得服务治理的难度前所未有,仅仅依靠微服务框架级的治理是不够的,构建一个高维深度的治理体系需要解决。 治理是指建立和实施微服务如何协同工作以实现系统设计和构建的业务目标的过程,服务不要超出其上下文边界非常重要。 服务治理可以通过多种方式实现:
追踪工具:Sleuth、Zipkin、Htrace
② 服务注册和发现
在云服务器架构时代,单个大型单体应用程序被分解成更小的可单独部署的单元,称为微服务。 当一个服务想要和其他服务通信时,它需要知道远端的 IP 地址和端口号。一种直接的解决方案是维护一个配置文件,其中包含目标服务的 IP 地址和端口,这有很多缺点,其中之一是云可扩展性。云提供了根据当前负载扩展和缩小服务器实例的能力,遵循上述方法会使您处于无法利用此容量的情况。 这就是服务发现发挥作用的地方。它通过提供一种注册服务的方法来帮助解决上述问题,即当一个新服务启动并想要参与服务客户端请求时,它使用其 IP 和端口将自己注册到服务注册中心,并且这些信息可被客户端获取到。此外,还实施了运行状况检查监控,仅将流量转发到运行状况良好的实例。
③ 负载均衡
负载均衡是一种请求调度策略,可以协调多台服务器共同承担网络请求,从而扩展系统的处理能力。在后面的部分中,将了解如何使用 RSocket 在服务器池之间智能地负载平衡客户端请求。
二、边车模式
将应用程序的功能划分为运行在同一个调度单元中的独立进程,可视为sidecar 模式。Sidecar 模式允许抽象与应用程序业务逻辑无关的功能,从而降低代码的重复性和复杂性。可观察性、监控、日志记录、配置、断路器等问题可以在sidecar 容器中实现并部署在同一个单元上,比如 Kubernetes 上下文中的 Pod。
在 sidecar 模式下,代理容器可以与 Pod 中的应用程序容器共享一个网络命名空间。网络命名空间是 Linux 内核的结构,它允许容器和 Pod 拥有自己独立的网络堆栈,将容器化的应用程序相互隔离。这使得应用程序变得无关紧要,这就是为什么可以让尽可能多的 pod 在端口 80 上运行 Web 应用程序。代理将共享相同的网络命名空间,以便它可以拦截和处理进出应用程序容器的流量。
三、Service Mesh 之旅
① 微服务
微服务是一种架构风格,允许将具有单一职责和功能的多个单元以模块化的方式组合起来,形成一个非常复杂和大型的应用程序。 第一代微服务依靠内部 SDK 实现服务发现、熔断重试等功能(如 Spring Cloud)。从开发的角度来看,这代表着巨大的缺陷,因为开发人员将 SDK 包含在软件堆栈中,最终只依赖特定的编程语言,更不用说升级/部署成本、敏捷性原则(当 SDK 升级时,应用程序也需要升级),版本控制碎片和高学习曲线。即使业务逻辑没有改变,也可以添加到使用更新版本发布的应用程序中,这是非功能性代码与业务代码耦合的结果。
② 服务网格
Service Mesh 是一个基础设施层,用于通过 sidecar 模式处理服务之间的通信,以透明代理的形式提供安全、快速、可靠的服务间通信。
使用 Service Mesh,我们可以将 SDK 中的大部分能力从应用中剥离出来,拆解成独立的进程(容器),以 Sidecar 模式部署。通过将服务治理能力下沉到基础设施中,微服务会做一件事,专注于业务逻辑,它会做好。这样,Infrastructure 团队就可以更加专注于各种通用能力,真正实现自主演进、透明升级、提升整体效率。 Service Mesh 的基础设施层主要分为控制平面和数据平面两部分。两个流行的开源服务网格是 Istio 和 Linkerd。我们稍后将注意力转移到 Istio。 服务网格在整体架构上还是比较简单的,但只是各种服务旁边的一堆用户代理,加上一套任务管理流程。代理在服务网格中称为数据层或数据平面,管理过程称为控制层或控制平面。数据层拦截不同服务之间的调用并“处理”它们;控制层协调代理的行为,并提供 API 或命令行工具来配置版本管理以实现持续集成和部署。 服务不直接通过网络调用服务,而是调用其本地的 sidecar 代理,这些代理依次代表服务管理请求,封装了服务间通信的复杂性。
四、Istio 快速浏览
① Istio 架构
Istio 是一个面向云原生场景的 Service Mesh 形式的服务治理开放平台,与 Kubernetes 紧密集成,Istio 提供负载均衡、服务之间的身份验证、监控等功能。 Istio 的架构分为控制平面和数据平面:
数据平面:它由整个网格中的 sidecar 代理组成,这些代理与应用服务一起以 sidecar 的形式部署,每个 sidecar 都会接管服务的进出流量,并配合控制平面完成流量控制等功能。
控制平面:顾名思义,在数据平面控制和管理 sidecar 代理,完成配置分发、服务发现、授权认证等功能。在架构中有控制平面的好处是可以统一管理数据平面。
② 核心组件
③ Envoy
Envoy 是用 C++ 开发的高性能代理,Istio 服务网格将 Envoy 代理注入为位于应用程序容器旁边的边车容器,并拦截服务的所有入站和出站流量,并执行不同的功能,例如负载平衡、断路器、故障注入和暴露 pilot 代理指标给 Prometheus 和 Jeager 收集。注入的代理一起形成服务网格的数据平面。
④ Istiod
Istiod 是一个控制平面组件,用于提供服务发现、配置和证书管理功能,Istiod 采用 YAML 编写的高级规则,并将其转换为 Envoy 的可操作配置,然后它将这个配置传播到网格中的所有边车。 Pilot Pilot 组件的主要作用是将路由规则等配置信息转化为 sidecar 可以识别的信息,发送到数据平面。可以简单理解为一个配置分发器,辅助 sidecar 完成流量控制相关的功能。 Citadel: Citadel 是 Istio 中的一个安全组件,它生成证书以允许数据平面中代理之间的安全 mTLS 通信。 Galley: Galley 是 Istio 1.1 版本中的一个新组件,旨在将 Pilot 与 Kubernetes 等底层平台解耦。它共享原 Pilot 的部分功能,主要负责配置的校验、提取和处理功能。
⑤ Istio 流量转发
入站处理程序配置为将下游流量转发到主应用程序容器,另一方面,出站处理程序侦听所有出站流量并将其转发到上游。Istio 使用 Init Container 对 Pod 的 Network Namespace 中的 iptables 进行操作并设置规则,以便将 Pod 的入站/出站数据包传输到 Sidecar。 init 容器在以下方面不同于应用程序容器:
提到 Service Mesh,你首先想到的可能就是 Istio + Envoy 的 SideCar 的 Service Mesh 架构,目前非常流行。虽然乍一看这种方法没有明显的问题,但仍有几点值得考虑:
性能下降:代理是一个独立的应用程序,需要特定的资源,例如 CPU 和内存。Envoy 通常需要大约 1G 的内存;
架构复杂性:需要控制平面、数据平面、不同应用的规则推送、Proxy 之间的通信安全等;
运维成本增加:没有自动化运维工具,就无法部署 Sidecar,Service Mesh 的典型解决方案是基于 Kubernetes,减少了很多工作量。
五、eBPF
正如可能已经观察到的那样,使用 sidecar 模式,需要在每个单元上部署一个具有适当配置的容器。如果仔细观察,每个节点只有一个内核;在一个节点上运行的所有容器共享同一个内核,不能利用它来将部署的 sidecar 代理的数量减少到节点的数量吗?这将我们引向 eBPF。 eBPF 是一种内核技术,允许自定义程序在内核中运行。这些程序响应事件运行。有数以千计的可能事件,并且 eBPF 程序可以附加到这些事件。这些事件包括轨迹点、访问或退出任何功能(在内核或用户空间中)或对服务网格很重要的网络数据包。如果你将一个 eBPF 程序添加到一个事件到内核中,它就会被触发,不管是哪个进程导致了这个事件,它是运行在应用程序容器中还是直接运行在主机上。无论是在寻找可观察性、安全性还是网络, eBPF 驱动的解决方案可以在没有 sidecar 的情况下检测应用程序。
2021 年 12 月 2 日,Cilium 项目宣布了 Cilium Service Mesh 的 beta 测试计划:
https: / / cilium. io/ blog/ 2021 / 12 / 01 / cilium- service- mesh- beta
基于 eBPF 的 Cilium 项目将这种“无边车”模型引入服务网格世界:
http: / / cilium. io/
以处理服务网格中的大部分边车代理功能,包括 L7 路由、负载平衡、TLS、访问策略、健康检查、日志记录和跟踪:
① YAML 减少
在 sidecar 模型中,需要修改指定每个应用程序 pod 的 YAML 以添加 sidecar 容器,这通常是自动化的。例如,使用 mutating webhook 在每个应用程序 pod 部署时注入 sidecar。 以 Istio 为例,它需要标记 Kubernetes 命名空间和 Pod 来定义是否应该注入 sidecar。
但是如果出现问题怎么办?如果命名空间或 Pod 没有被正确标注,sidecar 将不会被注入,Pod 也不会连接到服务网格。更糟糕的是,如果攻击者破坏了集群并且可以运行恶意工作负载,则不会通过服务网格提供的流量观察能力被发现。 相比之下,在支持 eBPF 的无 sidecar 代理模型中,无需任何额外的 YAML 即可检测到 pod。相反,CRD 用于配置集群内的服务网格。即使是现有的 pod 也可以成为服务网格的一部分,而无需重新启动。 此外,当攻击者试图通过直接在主机上运行工作负载来规避 Kubernetes 编排时,eBPF 将检测并控制此活动,因为所有这些都可以从内核中看到。
② 网络效率
在启用 eBPF 的网络中,数据包可以绕过内核的一些网络堆栈,这可以提高性能,看看这如何应用于服务网格数据平面:
在 eBPF 加速和无 sidecar 的服务网格模型中,网络数据包通过的路径要短得多。 在服务网格的情况下,代理在传统网络中作为 sidecar 运行,数据包到应用程序的路径相当长:入站数据包必须跨越主机 TCP/IP 堆栈并通过虚拟以太网连接到网络命名空间 Pod 。从那里,数据包必须通过 Pod 的网络堆栈才能到达代理,代理通过环回接口将数据包转发给应用程序。考虑到流量必须流经连接两端的代理,与非服务网格流量相比,这将导致延迟显着增加。 基于 eBPF 的 Kubernetes CNI 实现,例如 Cilium,可以使用 eBPF 程序明智地挂钩内核中的特定点,并沿着更直接的路线重定向数据包。这是可能的,因为 Cilium 知道所有 Kubernetes 端点和服务的身份。当数据包到达主机时,Cilium 可以直接将其分配给它想要的代理或 Pod 端点。
③ 网络加密
服务网格通常用于确保所有应用程序流量都经过身份验证和加密。通过双向 TLS (mTLS),服务网格代理组件充当网络连接的端点,并与远程对等方协商安全的 TLS 连接。该连接在不更改应用程序的情况下加密代理之间的通信。 TLS 的应用层实现并不是实现组件间身份验证和加密流量的唯一方法。也可以使用 IPSec 或 WireGuard 在网络层加密流量。因为它在网络层运行,所以这种加密不仅对应用程序完全透明,而且对代理也完全透明。它可以在有或没有服务网格时启用。如果您使用服务网格的唯一原因是提供加密,您可能需要考虑网络级加密。它不仅更简单,而且还用于验证和加密节点上的任何流量,它不仅限于启用了 sidecar 的工作负载。
六、RSocket 代理
RSocket 路由代理是使用 RSocket 协议的各种应用程序之间的通信系统:
RSocket Broker 的工作原理是:服务调用者(Requester)向 Broker 发起服务调用请求,Broker 将请求转发给服务提供者(Responder),Broker 最终将响应者的处理结果返回给请求者。
当一个服务提供者应用程序启动时,它会主动与 Broker 建立一个长 TCP 连接,然后告诉 Broker 它可以服务的服务列表。 当服务消费者应用程序启动时,它还会与 Broker 创建一个长 TCP 连接。当消费者应用要调用远程服务时,服务消费者将服务调用请求封装为消息(用唯一的消息 ID 标识)发送给 Broker。broker 收到消息后,根据浮现出来的元信息解析出需要调用的服务,然后在内部的服务路由表中查找可以调用的服务。 服务提供者处理请求后,将处理结果封装为消息发送回 Broker。Broker 根据消息 ID 将返回的消息转发给服务调用者。请求消费响应消息并执行相应的业务逻辑。 这种基于 Broker 的消息通信方式具有以下优点:
不监听端口:服务提供者不再监听端口,与 HTTP REST API 和 gRPC 完全不同,更安全;
通信透明:请求者和服务提供者不需要感知对方的存在;
流量控制:如果服务提供者压力太大,broker 会自动将消息转发给其他服务提供者(智能负载均衡),这可以通过租约来实现 服务注册与发现:无需第三方注册,如 Eureka、Consul、ZooKeeper 等,降低基础设施依赖成本;
安全性:Broker 会验证服务提供者和服务消费者的访问权限,只需要在 Broker 上部署 TLS 支持即可保证通信通道的安全。 Broker 也有一些缺点。由于双方之间没有通信,因此性能略有下降。另外,所有的通信流量都是通过 Broker 转发的,所以网络存在瓶颈,但是可以通过集群和 Broker 的高可靠性来缓解。
七、通过 RSocket Broker 进行服务治理
作为 Service Mesh 解决方案,Istio 实际上很难应用到数据中心之外,物联网设备呢?在每部手机上安装边车?这就是 RSocket 代理出现的地方。 RSocket 路由代理可用于实现 Service Mesh,在下面的方案中,没有边车运行,也没有重复的进程。
以下是两种架构方案的典型特征对比:
基础设施层:一方面是 sidecar 代理+控制平面,另一方面是具有集成控制平面功能的集中式代理。
集中化管理:集中化将使管理更加全面,例如 Logging、Metrics 等。
通信协议:RSocket 方案的一个缺点是应用程序之间必须使用 RSocket 通信协议。
应用程序或设备访问:并非所有设备都可以安装 Proxy。有几个主要原因:不支持设备和系统本身,例如物联网设备;这就是基于 RSocket 的方案具有巨大优势的地方。
运维成本增加:管理一个 10 台服务器组成的 RSocket Broker 集群和管理 10K 个 Proxy 实例是不一样的。
效率:RSocket 协议性能比 HTTP 高 10 倍。
安全性:RSocket 的安全性实现更简单。Broker 主要是 TLS+JWT,不是 mTLS,不需要证书管理。同时,借助 JWT 的安全模型,轻松实现更细粒度的权限控制。使用 RSocket 代理方案,可以减少攻击面。
网络和基础设施依赖:RSocket Broker 相对于 Istio 的一大优势就是不依赖 Kubernetes,虽然 Istio 也声称不依赖 Kubernetes,但是在 Kubernetes 之外部署和管理 Sidecar 代理并不简单,而 RSocket Broker 可以部署在任何地方。