Service Mesh学习笔记

978 阅读11分钟
很长一段时间以来,传统的软件应用程序一般都是作为单个项目开发的,这种情况适用于小型软件应用程序的开发。然而不断扩展的功能要求意见,对互联网级规模使用模式的需求,不可避免地导致了这些代码库日益庞大,复杂,不灵活。由于大部分的代码紧密耦合,这些单体应用程序变得越来越难以维护和操作,即使某一功能的细微变化也可能导致意想不到的整体应用的变化。尤其是在当下缩短软件发布周期的竞争浪潮中,现代应用程序需要进行快速的更新迭代,功能升级,运维。

1.微服务

微服务(Microservices)自2012年被提出以来,就继承了传统SOA架构的基础,并在理论和工程实践中形成新的标准,热度不断攀升,甚至有成为默认软件架构的趋势。2014年,马丁·福勒在Microservices一文中,对微服务做出了纲领性的定义,总结了微服务应该具备的特点,如下所述。
  • 在结构上,将原有的从技术角度拆分的组件,升级为从业务角度拆分的独立运行的服务,这些服务具备各自的实现平台,并且独占自有数据,在服务之间以智能端点和哑管道的方式通信。
  • 在工程上,从产品而非项目的角度进行设计,强调迭代、自动化和面向故障的设计方法。
提倡将单一应用划分成一组小的服务,服务之间相互协调,相互配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务和服务之间采用轻量级的通信机制(通常是基于HTTP的Restfu API)。每个服务都围绕着具体的业务进行构建,并且能够被独立地部署到测试环境或者生产环境。对具体的一个服务而言,应根据业务上下文,选择合适的语言,工具对其进行构建。
由此可见,微服务是一种小型的,可独立部署的且可独立扩展的软件服务,目的是将特定语义功能封装在更大的应用程序中。

2.Kubernetes

云改变了我们消费基础设施的方式,并改变了我们构建应用程序的条件。微服务,DevOps和云服务等技术能带来开发的灵活性,然而,在任何新方法或技术转变带来巨大的收益的同时,新的挑战也随之而来并不可避免。微服务架构在很大程度上提高了应用的伸缩性,方便了部门或业务之间的协作,使技术岗位能够更好地引入新技术并提高自动化程度,最终达到减耗增效的目的。然而和所有新方法一样,微服务架构在解决老问题的同时,也带来了一些新问题,例如:
  • 实例数量急剧增长,对部署和运维的自动化要求更高;
  • 用网络调用代替内部API,对网络这一不可靠的基础设施依赖增强;
  • 调用链路变长,分布式跟踪成为必选项目;
  • 日志分散严重,跟踪和分析难度加大;
  • 服务分散,受攻击面积更大;
  • 在不同的服务之间存在协作关系,需要有更好的跨服务控制协调能力;
  • 自动伸缩、路由管理、故障控制、存储共享,等等。
幸运的是早期的微服务实践者们已经慷慨的分享了他们在微服务方面的实践,并贡献了源码到社区中,例如,Spring Cloud微服务开发全家桶,阿里巴巴开源的微服务框架Dubbo,Netflix向开源社区开发的微服务库等。具体来说,在实际项目开发过程中,对于Java程序员,如果使用的Spring Cloud等微服务框架,那么势必会使用其程序库处理了云原生的一些问题,包括:
  • 熔断--Hystrix
  • 客户端负载均衡--Ribbon
  • Eureka--服务组册和发现
  • Zuul--动态代理
由于这些库都是针对Java运行时的,因此只能用于Java项目。但,复杂的系统中的微服务实现往往会使用不同的编程语言,不同的框架,这些实现方案往往存在差异大,缺少共性的问题。另一方面,这些基本的应用程序网络问题并非特定于某个应用程序,语言或框架。例如,重试,超时,客户端负载均衡和熔断等,这些问题与应用程序功能本身相互独立。作为整个服务的一部分,它们是关键问题,但是为使用的每种语言或框架投入大量的时间和资源,以便在特定的语言或框架中实现类似功能,这应该不是最佳的解决方法。我们真正想要的是以一种技术无关的方式来解决这些问题,并非特定于应用程序本身来实现。
Linux容器简化了应用程序的打包部署,容器是云原生应用的基石。而容器编排更近一步,负责解决如何高效地编排和利用好这些资源。Kubernetes编排容器服务已经成为一种事实标准。无论使用什么具体的开发语言和编程框架,针对应用的构造,部署,服务暴露,服务关联,健康检查和扩展等,通过使用Kubernetes即可将其提升到新的水平。Kubernetes也有一个简单的负载均衡和服务发现机制。Kubernetes是一个出色的容器部署和管理平台,以容器技术为基础,在进程级别为微服务提供了一致的部署、调度、伸缩、监控、日志等功能。然而,除了进程本身的问题,微服务之间的通信和联系更加复杂,其中的观测、控制和服务质量保障等都成为微服务方案的短板,因此,随着Kubernetes成为事实标准,Service Mesh顺势登场。

                                                                  容器化部署的演进

设计良好的分布式系统都必须遵循最佳实践和原则,以使其功能正常运行。Kubernetes不仅是一个管理系统,它同时还可应用这些最佳实践为开发者和管理员提供高水平的服务。Kubernetes中的几种设计模式:

1.边车模式

车模式除主应用容器之外,还在Pod中共同定位另一个容器。应用容器并不知道边车容器,只是单纯执行自己的任务。中央日志代理(Central Logging Agent)就是一个很好的例子。主容器只将日志记录到stdout,但边车容器会将所有日志发送到一个中央日志服务,这些日志将在此处聚合整个系统的日志。使用边车容器相较于将中央日志添加到主应用容器有巨大的优势,应用不再受到中央日志的负担,如果要升级或更改中央日志记录策略或切换到新的提供商,只需更新并部署边车容器,应用容器并没有任何改变,因此不会由于意外情况而遭到破坏。

2.外交官模式
外交官模式是指将远程服务当作本地服务,并使其强制执行部分策略。外交官模式的一个很好的例子是,如果有一个Redis集群,该集群中一个主机用于编写,其余副本用于读取,则本地外交官容器可作为代理,并将Redis暴露给本地主机上的主应用容器。主应用容器简单地连接到localhost:6379(Redis缺省端口)上的Redis,但是它其实只是连接到在相同Pod中运行的外交官容器,该容器过滤请求,将编写请求发送到真正的Redis主机,并将读取请求随机发送到其中一个读取副本上,与挎斗模式类似,主应用在这期间并不了解运行过程。当测试真正的本地Redis集群时,这会有很大的帮助。此外,如果Redis集群配置发生改变,则只需要修改外交官容器,主应用同样不了解这一运行过程。
3.适配器模式
适配器模式是关于主应用容器的标准化输出。逐步推出的服务可能会面临如下问题:服务可能会生成不符合先前版本的格式报表,而其他使用该输出的服务和应用还未升级。适配器容器可以与新的应用容器共同部署在同一Pod上,并将其输出与旧版本相匹配,直到所有的用户都被升级。适配器容器与主应用程序容器共享文件系统,以此监控本地文件系统,每当新应用写入某个文件时,适配器容器将立即进行适配。
4.多节点模式单节点模式都是直接由Kubernetes通过Pod直接进行支持的。而多节点模式并不被直接支持,例如负责人选举、工作队列和分散收集等,但使用标准接口组合Pod可实现Kubernetes支持。

3.Service Mesh

Service Mesh是什么?
Service Mesh是用于处理服务与服务之间通信的专用基础设施层;在具有复杂拓补结构的现代云原生服务间,它负责请求的可靠交付。在具体实践中,Service Mesh通常实现为一系列的轻量级网络代理,这些代理与应用程序代码一起部署,对应用程序是透明的。
以上这段话有四个关键点:
  • 本质:基础设施层。
  • 功能:请求分发。
  • 部署形式:网络代理。
  • 特点:透明。

2017 年,随着 Linkerd 的传入,Service Mesh进入国内社区的视野,并且由国内的技术布道师们翻译成“服务网格”。

服务网格从总体架构上来讲比较简单,不过是一堆紧挨着各项服务的用户代理,外加一组任务管理流程组成。代理在服务网格中被称为数据层或数据平面(data plane),管理流程被称为控制层或控制平面(control plane)。数据层截获不同服务之间的调用并对其进行“处理”;控制层协调代理的行为,并为运维人员提供 API,用来操控和测量整个网络。

更进一步地说,服务网格是一个专用的基础设施层,旨在“在微服务架构中实现可靠、快速和安全的服务间调用”。它不是一个“服务”的网格,而是一个“代理”的网格,服务可以插入这个代理,从而使网络抽象化。在典型的服务网格中,这些代理作为一个 sidecar(边车)被注入到每个服务部署中。服务不直接通过网络调用服务,而是调用它们本地的 sidecar 代理,而 sidecar 代理又代表服务管理请求,从而封装了服务间通信的复杂性。相互连接的 sidecar 代理集实现了所谓的数据平面,这与用于配置代理和收集指标的服务网格组件(控制平面)形成对比。

总而言之,Service Mesh 的基础设施层主要分为两部分:控制平面与数据平面。当前流行的两款开源服务网格 Istio 和 Linkerd 实际上都是这种构造。
使用 Service Mesh 并不是说与 Kubernetes 决裂,而是水到渠成的事情。Kubernetes 的本质是通过声明式配置对应用进行生命周期管理,而 Service Mesh 的本质是提供应用间的流量和安全性管理以及可观察性。假如你已经使用 Kubernetes 构建了稳定的微服务平台,那么如何设置服务间调用的负载均衡和流量控制?
Envoy 创造的 xDS 协议被众多开源软件所支持,如 Istio、Linkerd、MOSN 等。Envoy 对于 Service Mesh 或云原生来说最大的贡献就是定义了 xDS,Envoy 本质上是一个 proxy,是可通过 API 配置的现代版 proxy,基于它衍生出来很多不同的使用场景,如 API Gateway、Service Mesh 中的 Sidecar proxy 和边缘代理。

当然,Service Mesh目前也面临一些挑战:
  • Service Mesh组件以代理模式计算并转发请求,一定程度上会降低通信系统性能,并增加系统资源开销;
  • Service Mesh组件接管了网络流量,因此服务的整体稳定性依赖于Service Mesh,同时额外引入的大量Service Mesh服务实例的运维和管理也是一个挑战;