一、ServiceMesh概念

背景

        随着业务的发展,传统单体应用的问题越来越严重:

  • 单体应用代码库庞大,不易于理解和修改
  • 持续部署困难,由于单体应用各组件间依赖性强,只要其中任何一个组件发生更改,将重新部署整个应用,而频繁的部署将增加服务宕机的风险,因此频繁地进行部署几乎不可能
  • 扩展应用困难,单体应用只能从一个维度进行扩展,即很容易通过增加实例副本提供处理能力。另一方面,单体应用各个组件对资源的使用情况需求不同,一些是CPU密集型,另一些是内存密集型,但是不能独立地扩展单个组件
  • 阻碍快速开发,随着公司业务的发展,单体服务框架变得更加庞大,更多的部门将会参与系统的开发,但是各个部门又不能独立开发、维护相应的模块,即使其中一个部门完成相应的更新,仍然不能上线,因此需要花费更多时间在部门间协调和统一。还有,需要增加新的功能时,单体应用最初的设计限制开发人员灵活选择开发语言、工具等,导致新功能上线慢
  • 迫使开发人员长期专注于一种技术栈,由于单体应用本身设计的原因,后期引入新的技术栈需要遵循最开始的设计,因此存在非常大的局限性、挑战性,否则可能需要重写整个框架。

        针对上面问题的出现,微服务架构应运而生,将单体应用拆分后由多个微服务构建的复杂系统,系统中各个微服务之间彼此通过网络进行通信,很好地解决了上述问题。而微服务中最大的挑战便是如何以标准化的方式管理微服务以及如何保证复杂网络环境中微服务间的可靠通信,确保整个系统的最大可用性,提供尽可能高的SLA。

        当单体应用拆分为微服务后,新的通信模型如下:

微服务构

每个微服务由两部分构成:

  • 业务逻辑:定义如何处理应用业务逻辑
  • 网络功能:网络功能部分主要负责服务间的通信,包括上述列出的构建分布式高可用的技术实现,如超时、重试、服务发现、负载均衡等,由于它基于下层网络协议栈实现,因此被称作网络功能

此时相对于传统的单体应用,网络功能部分可以通过一个中心化的组件来统一实现或者直接嵌入到业务逻辑中,但是在微服务架构中,服务的粒度变得更小,为了实现它们之间的可靠通信,开发人员为每个微服务实现网络功能比实现业务逻辑花费的时间和精力可能更多。

传统微服务架构

从软件设计的角度,存在以下缺点:

  • 耦合性很高,每个应用都需封装负载均衡、服务发现、安全通信以及分布式追踪等功能
  • 灵活性差,复用率低下,不同的应用需要重复实现
  • 管理复杂,当其中一项如负载均衡逻辑发生变化,需要更新所有服务
  • 可运维性低,所有组件均封装在业务逻辑代码中,不能作为一个独立运维对象
  • 对开发人员能力要求很高

随着不断发展,考虑将应用处理服务发现、负载均衡、分布式追踪、安全通信等设计为一个公用库,从而使得应用与这些功能具有更低的耦合性,而且更加灵活、提高利用率及运维性。

微服务新架构

而这种方案也存在不足之处:

  • 如果将类似Finagle、 Proxygen或者Zipkin的库集成现有的系统中,仍然需要花费大量的时间、人力将其集成到现有生态圈,甚至需要调整现有应用的代码。
  • 缺乏多语言支持,由于这些库只针对某种语言或者少数几种语言,这使得在一个多技术栈的公司中需要限制开发语言和工具的选择
  • 虽然公共库作为一个独立的整体,但在管理复杂性和运维性这些方面仍然有更大的提升空间
  • 公共库并不能完全使得开发人员只关注业务代码逻辑,仍然需要对公共库有很深的认识

        针对上面面临的问题,发现了更好的解决方案,OSI定义了开放系统的层次结构、层次之间的相互关系以及各层所包括的可能的任务,上层并不需要对底层具体功能有详细的了解,只需按照定义的准则协调工作即可。因此,我们也可参照OSI七层模型将公用库设计为位于网络栈和应用业务逻辑之间的独立层,即透明网络代理,新的独立层完全从业务逻辑中抽离,作为独立的运行单元,与业务不再直接紧密关联。通过在独立层的透明网络代理上实现负载均衡、服务发现、熔断、运行时动态路由等功能,该透明代理在业界有一个非常新颖时髦的名字:Service Mesh。率先使用这个Buzzword的产品恐怕非Buoyant的Linkerd(https://linkerd.io/)莫属了,随后Lyft也发布了他们的Service Mesh实现Envoy(https://github.com/envoyproxy/envoy),之后Istio(https://istio.io/)也迎面赶上,成为Service Mesh领域非常热门的一个项目。

Service Mesh架构

        在这种方案中,Service Mesh作为独立运行层,它很好地解决了上述所面临的挑战,使应用具备处理网络弹性逻辑和提供可靠交互请求的能力。它使得耦合性更低、灵活性更强,跟现有环境的集成时间和人力代价更小,也提供多语言支持、多协议支持,运维和管理成本更低。最主要的是开发人员只需关注业务代码逻辑,而不需要关注业务代码以外的其他功能,即Service Mesh对开发人员是透明的。

什么是Service Mesh

        Service Mesh的发起人、先驱者,Buoyant公司的CEO William Morgan,他对Service Mesh的定义如下:

  • 专用基础设施层:独立的运行单元
  • 包括数据平面和控制平面:数据平面负责交付应用请求,控制平面控制服务如何通信
  • 轻量级透明代理:实现形式为轻量级网络代理
  • 处理服务间通信:主要目的是实现复杂网络中服务间通信
  • 可靠地交付服务请求:提供网络弹性机制,确保可靠交付请求
  • 与服务部署一起,但服务感知不到:尽管跟应用部署在一起,但对应用是透明的

        Service Mesh架构如下,告诉Service Mesh控制层和数据层在微服务架构中所处位置、服务间通信模式以及提供的各种功能

Service Mesh控制层和数据层图

        Service Mesh是一种用于处理微服务架构中服务间通信的基础设施层。它的主要功能是提供可靠的网络通信,并在服务间通信中实现负载均衡、流量管理、安全认证、监控和故障处理等功能。Service Mesh通过在应用程序中部署轻量级代理(通常称为Sidecar)来实现这些功能,这些代理负责拦截和处理服务之间的所有网络流量。

Service Mesh的核心组件

        Service Mesh的架构通常包括以下几个核心组件:

  1. 数据平面(Data Plane)

    • Sidecar Proxy:每个服务实例旁边运行的代理,负责拦截出入的网络流量并执行流量管理、安全策略等操作。常见的Sidecar Proxy包括Envoy、Linkerd-proxy等。

    • Service Proxy:在某些实现中,代理可能直接嵌入到服务实例中,作为服务的一部分运行。

  2. 控制平面(Control Plane)

    • 配置管理:提供统一的配置管理接口,用于下发和管理数据平面的配置。常见的控制平面包括Istio的Pilot、Linkerd的Controller等。

    • 服务发现:管理服务注册和发现,确保代理能够正确路由流量。

    • 策略管理:用于定义和下发流量管理、安全认证、访问控制等策略。

    • 可观察性组件:负责收集和聚合服务网格中的监控数据、日志和追踪信息,提供可视化和报警功能。

Service Mesh的工作原理

        Service Mesh通过在每个服务实例旁边部署Sidecar Proxy,实现了对服务间通信的透明代理。这些代理负责拦截出入的所有流量,并根据控制平面下发的配置和策略执行相应的操作。具体工作原理如下:

  1. 服务发现

    • 当一个服务实例启动时,它会向服务注册中心注册自己的信息。控制平面负责管理这些服务实例信息,并将更新的服务列表分发给所有Sidecar Proxy。

  2. 流量管理

    • 当一个服务需要与另一个服务通信时,流量首先经过本地的Sidecar Proxy。代理根据配置的路由规则和负载均衡策略,将流量转发到目标服务实例。

    • 控制平面可以动态更新这些路由规则,实现蓝绿部署、金丝雀发布等高级流量管理功能。

  3. 安全认证

    • Service Mesh可以在服务间通信中引入双向TLS加密,确保数据在传输过程中不被篡改和窃听。控制平面负责管理和分发证书,Sidecar Proxy在通信过程中进行加密和解密操作。

    • 通过引入身份认证和访问控制策略,可以细粒度地控制哪些服务可以访问其他服务。

  4. 可观察性

    • Service Mesh中的代理会收集每个请求的日志、监控数据和追踪信息,并将这些数据发送到可观察性组件进行处理和存储。

    • 运维人员可以通过控制平面提供的接口和仪表盘,实时监控服务间的流量情况、延迟、错误率等指标,并进行故障排查和性能优化。

常见Service Mesh框架介绍

        目前市场上有多种Service Mesh框架,每种框架在功能、性能和易用性上都有不同的特点。以下是几个常见的Service Mesh框架:

  1. Istio

    • 概述:Istio是目前最流行的Service Mesh框架之一,具有丰富的功能和广泛的社区支持。它采用Envoy作为数据平面代理,并提供了强大的控制平面组件(Pilot、Mixer、Citadel等)。

    • 特点:支持复杂的流量管理、强大的安全特性和丰富的可观察性功能。

    • 应用场景:适用于需要复杂流量控制和高级安全特性的企业级应用。

    • 架构图:

  2. Linkerd

    • 概述:Linkerd是一个轻量级的Service Mesh框架,专注于简单易用和性能优化。它最初由Buoyant开发,使用Linkerd2时采用了Rust编写的轻量级代理(Linkerd2-proxy)。

    • 特点:安装和配置简单,性能高效,适合资源受限的环境。

    • 应用场景:适用于需要快速部署和高性能的微服务架构。

  3. Consul Connect

    • 概述:Consul Connect是HashiCorp的Service Mesh解决方案,集成了Consul的服务发现和健康检查功能。它使用Envoy作为数据平面代理,并提供了内置的服务网格功能。

    • 特点:与Consul的无缝集成,提供了强大的服务发现和健康检查功能。

    • 应用场景:适用于已经使用Consul进行服务发现的环境。

二、ServiceMesh核心技术

服务发现与负载均衡

服务发现

        服务发现是Service Mesh的基本功能之一,用于识别和跟踪微服务实例的地址和状态。服务发现机制主要包括以下两种方式:

  1. 客户端服务发现

    • 原理:客户端负责向服务注册中心查询目标服务实例的地址,并直接与这些实例进行通信。

    • 优点:实现简单,适合小规模部署。

    • 缺点:客户端需要处理服务注册和实例健康检查逻辑,增加了复杂性。

  2. 服务端服务发现

    • 原理:服务端代理(如Sidecar Proxy)负责与服务注册中心通信,客户端只需将请求发送到代理,代理根据查询到的服务实例信息进行转发。

    • 优点:客户端无需关心服务发现的细节,简化了应用程序逻辑。

    • 缺点:依赖服务端代理的高可用性和性能。

        常见的服务发现工具包括Consul、Eureka和Kubernetes的内置服务发现机制。Service Mesh通常采用服务端服务发现方式,通过控制平面与这些工具集成,动态更新Sidecar Proxy的路由表。

负载均衡

        负载均衡是优化服务间流量分配、提高系统整体性能的重要机制。Service Mesh提供了多种负载均衡策略,包括:

  1. 轮询(Round Robin)

    • 原理:按照固定顺序轮流将请求分配给可用的服务实例。

    • 优点:实现简单,分配均匀。

    • 缺点:不考虑服务实例的性能和负载情况。

  2. 随机(Random)

    • 原理:随机选择一个可用的服务实例处理请求。

    • 优点:实现简单,避免热点问题。

    • 缺点:同样不考虑服务实例的性能和负载。

  3. 最少连接(Least Connections)

    • 原理:将请求分配给当前连接数最少的服务实例。

    • 优点:能够较均匀地分配负载。

    • 缺点:需要实时监控和更新连接数,增加系统开销。

  4. 加权轮询(Weighted Round Robin)

    • 原理:根据服务实例的权重分配请求,权重越高分配的请求越多。

    • 优点:可以根据服务实例的性能和资源分配请求。

    • 缺点:权重设置和调整较复杂。

  5. 哈希一致性(Consistent Hashing)

    • 原理:基于请求的特定属性(如客户端IP)计算哈希值,并将请求分配给对应的服务实例。

    • 优点:保证同一属性的请求总是分配到同一实例,适合缓存场景。

    • 缺点:对负载均衡不均匀的情况可能不适用。

断路器与熔断机制

        断路器(Circuit Breaker)和熔断机制(Fallback Mechanism)是保障系统稳定性和容错能力的关键技术。

断路器

        断路器用于检测和应对服务调用失败,防止连锁故障导致系统崩溃。它的工作机制如下:

  1. 关闭状态(Closed)

    • 行为:正常转发请求。

    • 监控:统计请求的成功和失败率。

  2. 打开状态(Open)

    • 行为:直接拒绝请求,返回错误响应。

    • 触发:当失败率超过预设阈值,断路器进入打开状态。

  3. 半开状态(Half-Open)

    • 行为:允许少量请求通过,监控其结果。

    • 恢复:如果这些请求成功率高,断路器恢复到关闭状态;否则,重新进入打开状态。

        通过断路器机制,可以在服务故障时快速响应,避免进一步的资源浪费和系统崩溃。

熔断机制

        熔断机制是在断路器触发时,提供备用路径或降级服务以保证系统的基本功能。常见的熔断策略包括:

  1. 静态熔断

    • 原理:在配置文件中预定义熔断策略,当断路器触发时执行。

    • 优点:实现简单,适用于固定的应急处理。

  2. 动态熔断

    • 原理:根据实时监控数据动态调整熔断策略。

    • 优点:更灵活,能够根据实际情况进行调整。

    • 缺点:实现复杂,需要高质量的监控数据和分析能力。

数据平面与控制平面

数据平面

        数据平面负责处理服务间的实际网络流量,执行负载均衡、路由、断路器、熔断等操作。主要组件包括:

  1. Sidecar Proxy:如Envoy、Linkerd-proxy,负责拦截和处理服务间的流量。

  2. Ingress/Egress Gateway:用于处理外部流量的入口和出口,控制服务与外部系统之间的通信。

数据平面的关键特性:

  • 低延迟和高吞吐量:确保流量处理的效率和性能。

  • 可编程性:支持动态配置和策略调整。

  • 安全性:支持TLS加密、身份认证和访问控制。

控制平面

        控制平面负责管理和配置数据平面,提供统一的接口和管理功能。主要组件包括:

  1. 配置管理:负责下发和管理数据平面的配置,如Istio的Pilot。

  2. 策略管理:定义和下发流量管理、安全认证、访问控制等策略。

  3. 服务发现:管理服务注册和发现,如Consul、Eureka。

  4. 可观察性组件:收集和聚合监控数据、日志和追踪信息,如Prometheus、Jaeger。

控制平面的关键特性:

  • 集中管理:提供统一的配置和管理接口,简化运维操作。

  • 动态调整:支持实时配置和策略调整,适应快速变化的业务需求。

  • 高可用性和扩展性:确保控制平面自身的稳定性和可扩展性,避免成为单点故障。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐