第1章 服务网格

随着科技和互联网的发展,企业应用的规模不断扩大,系统的架构也从早期的单体应用逐渐演进到现在的微服务模式。随着微服务架构的普及和广泛应用,它已经成为分布式环境下非常流行的架构解决方案。然而,软件行业从来就没有“银弹”​,微服务虽然解决了业务耦合、扩展性和灵活性等问题,但同时也引入了新的问题:服务间通信成为困扰开发人员的新难题。在此背景下,服务网格(Service Mesh)技术诞生了。它的出现就是为了解决微服务架构中网络通信的难题,因此有些人把它称为下一代微服务。本章将简要地回溯软件架构的发展过程,并对微服务架构中面临的痛点做深入剖析,以便读者能体会到服务网格出现的背景和意义。然后本章会重点介绍服务网格的概念及其主要功能,并对目前市面上主流的服务网格产品做一个简要说明。

1.1 从单体应用到微服务

1.1.1 单体应用

单体架构(monolithic structure):顾名思义,整个项目中所有功能模块都在一个工程中开发;项目部署时需要对所有模块一起编译、打包;项目的架构设计、开发模式都非常简单。

当项目规模较小时,这种模式上手快,部署、运维也都很方便,因此早期很多小型项目都采用这种模式。

但随着项目的业务规模越来越大,团队开发人员也不断增加,单体架构就呈现出越来越多的问题:

  • 团队协作成本高:试想一下,你们团队数十个人同时协作开发同一个项目,由于所有模块都在一个项目中,不同模块的代码之间物理边界越来越模糊。最终要把功能合并到一个分支,你绝对会陷入到解决冲突的泥潭之中。

  • 系统发布效率低:任何模块变更都需要发布整个系统,而系统发布过程中需要多个模块之间制约较多,需要对比各种文件,任何一处出现问题都会导致发布失败,往往一次发布需要数十分钟甚至数小时。

  • 系统可用性差:单体架构各个功能模块是作为一个服务部署,相互之间会互相影响,一些热点功能会耗尽系统资源,导致其它服务低可用。

在上述问题中,相信大家在企业生产过程中应该深有体会,而要想解决这些问题,就需要使用微服务架构了。

1.1.2 微服务

微服务架构,首先是服务化,就是将单体架构中的功能模块从单体应用中拆分出来,独立部署为多个服务。同时要满足下面的一些特点:

  • 单一职责:一个微服务负责一部分业务功能,并且其核心数据不依赖于其它模块。

  • 团队自治:每个微服务都有自己独立的开发、测试、发布、运维人员,团队人员规模不超过10人(2张披萨能喂饱)

  • 服务自治:每个微服务都独立打包部署,访问自己独立的数据库。并且要做好服务隔离,避免对其它服务产生影响

例如,黑马商城项目,我们就可以把商品、用户、购物车、交易等模块拆分,交给不同的团队去开发,并独立部署:

那么,单体架构存在的问题有没有解决呢?

  • 团队协作成本高?

    • 由于服务拆分,每个服务代码量大大减少,参与开发的后台人员在1~3名,协作成本大大降低

  • 系统发布效率低?

    • 每个服务都是独立部署,当有某个服务有代码变更时,只需要打包部署该服务即可

  • 系统可用性差?

    • 每个服务独立部署,并且做好服务隔离,使用自己的服务器资源,不会影响到其它服务。

综上所述,微服务架构解决了单体架构存在的问题,特别适合大型互联网项目的开发,因此被各大互联网公司普遍采用。大家以前可能听说过分布式架构,分布式就是服务拆分的过程,其实微服务架构正式分布式架构的一种最佳实践的方案。

1.2 微服务架构的痛点

微服务相对于单体应用而言是一个巨大的进步,它将系统切分成若干个服务,使系统的复杂度降低,不同业务之间解耦并提高了可扩展性。另外,单个服务的复杂度大幅降低,这些服务由各自的团队负责开发和维护,高度内聚互不干涉,使得开发过程也变得更轻松。

但是,软件开发中从来就没有银弹。微服务在带来了一系列便利的同时,也伴随着新问题的出现。当一个大型的系统被拆分为几十个、上百个甚至更多的服务时,如何有效地管理服务,以及保证服务间的通信稳定可靠成为开发人员需要关注的新问题。

原本业务模块之间函数级别的调用方式变成了远程调用,单一的系统演变成了分布式系统。L Peter Deutsch等人提出的著名理论——分布式环境下的8个谬论,很好地总结了以微服务为代表的分布式系统在网络层面面临的问题:

  • 网络是可靠的

  • 网络延迟是0

  • 带宽是无限的

  • 网络是安全的

  • 网络拓扑结构从不改变

  • 只有一个管理员

  • 传输成本是0

  • 网络是均匀而稳定的

这些问题被定义为“谬论”​,其本质是要告诫开发人员,在构建分布式系统的过程中不要忽视它们,应该想办法去解决问题。因此,稳定可靠的网络通信成为构建微服务系统的一大难题。试想一个大型的业务系统,需要对成百上千个微服务进行版本控制、监控和故障转移等一系列操作,并实现A/B测试、灰度发布、限流、熔断和访问控制等一系列与网络相关的功能,这是多么复杂的一件事情。开发和运维人员在转型到微服务架构时不得不面对这一新的挑战。

1.3 服务网格的发展

为了解决微服务之间网络通信的问题,以应对这一全新的挑战,系统架构也进一步演化,最终催生了服务网格的出现。我们来回顾一下这一演进过程,以便读者能更好地理解服务网格的概念和存在的意义。

1.3.1 耦合阶段

在微服务架构中,服务发现、熔断这样的弹性能力是架构重要的组成部分。在单体应用中,可以使用一个公共的组件统一实现或是嵌入业务逻辑中。而在微服务架构下,因为服务的分散粒度更小,所以它变得更加复杂。起初开发人员将诸如熔断(Circuit Breaker)这样的网络层功能和业务代码封装在一起,使服务具备了网络控制能力,如图所示:

这种方案虽然易于实现,但从设计角度来讲缺点也很明显:

  • 网络功能和业务逻辑耦合

  • 每个服务都需要重复封装和实现这样的代码

  • 管理困难,如果某个服务的负载均衡发生了变化,则调用它的相关服务都需要更新变化

  • 开发人员不能专注在业务逻辑上。

1.3.2 封装公用库

一定有人会想,为什么不把服务发现处理、负载均衡、分布式追踪和安全通信等网络功能设计为一个公用库呢?这可以让应用与这些网络功能降低耦合,且更加灵活,提高了利用率及运维性,更重要的是开发人员只需要关注公用库,而不必自己实现这些功能,从而降低了开发人员的负担。图中展示了网络功能封装的情况:

实际上,一些大的软件公司(如Twitter和Facebook)都提供了这样的控件来解决这一问题。但即便如此,它仍然有一些不足之处:

  • 这些库有较为陡峭的学习成本曲线,需要耗费一定的时间和人力与现有系统集成,甚至需要修改现有代码去进行整合

  • 通常这种库是通过特定语言实现的,缺乏多语言的支持,和现有系统整合时会受到限制

  • 公共库的管理和维护依然牵扯了开发人员的大量精力

显然,把这些网络功能从服务中独立出来并单独部署才是更好的做法。它可以让工程师关注业务逻辑本身,而不必浪费时间在编写基础架构层的代码或者是管理三方库和框架上,如图所示:

1.3.3 Sidecar模式

然而,这样的方案仍然不完美,它会导致很多问题的出现,比如跨语言问题、更新后的发布和维护等。许多实践者发现,更好的解决方案是把它作为一个代理——服务不会直接访问它的下游依赖方,而是通过这个透明的代理来处理所有的流量。这就是Sidecar代理模式,也被翻译为边车代理,如图1-9所示。它是一个伴随服务的辅助进程,为服务提供额外的网络特性。可以理解为Sidecar就是服务的网络代理,服务所有的对外通信都由这个代理完成。Sidecar的出现要追溯到几年前,2013年,Airbnb开发了Synapse和Nerve,这是对Sidecar的一种开源实现。2014年,Netflix推出了Prana,这使得由不同语言实现的服务进行通信成为可能。

以Sidecar的方式进行网络代理,对应用服务没有侵入性,不会受到应用服务的语言和技术限制,而且可以做到控制层和业务逻辑的分开升级和部署。Sidecar在逻辑上和应用服务部署在同一个结点(如Pod)中,它们拥有相同的生命周期。每个服务都配备了一个Sidecar代理。Sidecar可以迅速方便地为应用服务提供扩展,而不需要应用服务的改造。它的主要功能如下:

  • Sidecar可以帮助服务注册到相应的服务发现系统,并对服务做相关的健康检查。如果服务不健康,则可以从服务发现系统中移除服务实例。

  • 当应用服务要调用外部服务时,Sidecar可以帮助从服务发现中找到相应外部服务的地址,然后进行服务路由。

  • Sidecar接管了进出的流量,这样我们就可以进行相应的日志监视、调用链跟踪、流控熔断等操作,这些都可以在Sidecar中实现

  • 服务控制系统可以通过Sidecar来控制应用服务,如流控、下线等。

于是,应用服务终于可以做到专注于业务逻辑。

1.3.4 服务网格出现

如果把Sidecar代理应用于一个大型的系统,其中包括多个相互通信的服务,那么每个服务都将有一个配套的Sidecar代理,服务之间通过Sidecar代理进行通信,最终得到一个如图所示的网络拓扑结构,这就是服务网格。

最后,总结一下微服务网络通信功能的演进过程:

  1. 最初,服务进行通信时,因为接收速度不一致,所以需要加入流量控制等功能(服务发现和熔断)

  2. 流控功能和业务耦合需要被标准化和复用,它们被封装在公共库里。

  3. 多语言多平台下,为避免浪费时间来开发和管理这些公共库,应将网络功能下沉并独立出来,和业务服务分离。

  4. 分离的通信服务发展成为Sidecar模式。

  5. Sidecar模式应用于多服务的系统,服务之间相互连接形成了网状拓扑结构,最终演变成了服务网格。

1.4 什么是服务网格

1.4.1 基本概念

服务网格(Service Mesh)这一名词在2016年9月由Buoyant公司的CEO William Morgan首先提出,并对其做了如下定义:

服务网格是一个处理服务通信的专门的基础设施层。它的职责是为构建复杂的云原生应用传递可靠的网络请求。在实践中,它是一组和应用服务部署在一起的轻量级的网络代理,对应用服务透明。

这段话有点晦涩难懂,但只要抓住下面几个关键点就能理解:基础设施、服务间通信、请求分发、云原生应用、网络代理和对应用服务透明。这些关键词清楚地对服务网格做出了解释:

  • 服务网格是什么(基础架构、网络代理)​

  • 主要功能(请求分发、发送)

  • 应用的场景(云原生应用)

  • 特点(透明)​

我个人对服务网格的定义是,服务网格是用来处理服务间通信的基础设施。可以说,服务网格就是Sidecar的网络拓扑形态,Mesh这个词也由此而来。

服务网格的出现解决了微服务框架中的痛点,使开发人员专注于业务本身。同时,将服务通信及相关管控功能从业务程序中分离到基础设施层。在云原生应用中,面对数百个甚至更多的服务,单个请求经由服务拓扑的路径可能会非常复杂,单独进行网络通信处理非常有必要,否则很难对整个应用的通信情况进行管理、监控和追踪。而这正是服务网格的意义所在。

1.4.2 服务网格的功能

那么服务网格到底能做什么呢?可以不夸张地说,作为微服务架构中负责网络通信的基础设施,服务网格具有网络处理的大多数功能。下面列举了一些主要的功能:

  • 动态路由:可以通过配置路由规则来动态确定要请求的服务。请求需要被路由到生产环境还是预演(Staging)环境?路由到本地还是云?是测试版本还是运行版本?所有这些路由规则都是可以动态配置的,而且能够应用到全部请求或者仅仅针对一部分请求。

  • 故障注入:Netflix有一个非常著名的故障测试系统Chaos Monkey,它会故意切断不同范围的网络环境来测试服务的容错能力。在服务网格中我们可以通过故障注入特性模拟基本的网络传输问题来验证系统的健壮性。

  • 熔断:生产环境中经常会有各种问题导致服务中断,这就需要系统有检测服务并且快速移除问题服务的能力。熔断可以通过服务降级来终止潜在的关联性错误。

  • 安全:微服务环境中,服务间通信变得更加复杂,如何保证这些通信是在安全、授权的情况下进行的就非常重要了。通过在服务网格上实现安全机制(如TLS加解密和授权)​,不但可以在不同的服务上对其进行重用,而且很容易在整个基础设施层更新安全机制,甚至无须对系统做任何操作。

  • 多语言支持:作为独立运行的透明代理,服务网格支持多语言的异构系统

  • 多协议支持:同多语言支持一样,实现多协议支持也非常容易

  • 指标和分布式追踪:服务网格对整个基础设施层的可见性使得它有能力对网络通信进行全面的检测,还可以收集指标和日志,并交由后端设施进行可视化展示

概括起来,服务网格主要具有如下4个主要的特性:

  • 可见性(Visibility)​:运行时指标遥测、分布式跟踪

  • 可管理性(Manage Ability)​:服务发现、负载均衡、运行时动态路由

  • 健壮性(Resilience)​:超时、重试、熔断等弹性能力

  • 安全性(Security)​:服务间访问控制、TLS加密通信

1.5 服务网格产品介绍

1.5.1 Linkerd

2016年初,前Twitter的两位工程师William Morgan和Oliver Gould组建了一个小的创业公司Buoyant,开发出了Linkerd并在GitHub上发布了0.0.7版本。这是业界公认的第一个Service Mesh。2017年年初Linkerd加入CNCF,同年4月1.0版本发布。同时,那篇著名的博客“What’s a service mesh? And why do I need one?”在Buoyant网站发布。

Linkerd使用Scala语言编写,底层基于Twitter的Finagle库。官方对Linkerd的定义是,一个开源的网络代理以服务网格的方式进行部署,专注于微服务通信的管理、控制和监控。它的功能特性有负载均衡、熔断、服务发现、动态路由、重试和超时等。

1.5.2 Envoy

2016年9月,Lyft公司的Matt Klein宣布Envoy在GitHub开源并发布了1.0.0版本。2017年Envoy加入CNCF成为第二个服务网格项目,并于2018年底孵化毕业。Envoy是一个高性能的C++语言实现的分布式代理,它也是一个通信总线。Envoy基于对Nginx、HAProxy、硬件负载均衡器和云负载均衡器等解决方案的了解,与每个应用服务一起运行,并以与平台无关的方式提供公共的网络特性。

Envoy具有以下功能特性:

  • 过程外架构:Envoy是一个自包含的高性能服务器,内存占用很小,可以与任何应用程序语言或框架一起运行。

  • HTTP/2和gRPC支持:Envoy对HTTP/2和gRPC的传入和传出连接都提供支持,它是一个透明的HTTP/1.1到HTTP/2的代理。

  • 负载均衡:支持先进的负载均衡能力,包括自动重试、断流、速率限制、请求镜像和区域本地负载均衡等。

  • API配置管理:Envoy为动态管理其配置提供了健壮的API。

  • 可视化:L7流量的深度可观测性,分布式跟踪的本地支持,MongoDB和DynamoDB数据层面的支持。

Envoy已经被印证性能优秀而稳定,既可作为独立的代理运行,也可以作为服务网格中的Sidecar代理和业务服务一起运行,负责网络通信。大量的厂商都在自己的生产环境中使用了Envoy,比如腾讯、Airbnb、Booking、DigitalOcean和eBay等。目前Envoy已经从CNCF项目中毕业,作为数据平面,以Sidecar代理的形式存在于Istio架构体系中。

1.5.3 Istio

2017年5月Istio的0.1版本发布,这标志着服务网格第二代产品的诞生,2018年7月Istio又发布了1.0版本。Istio是Google、IBM和Lyft联合发布的产品,靠着这3家公司的强大支持,它很可能成为继Kubernetes之后的另一个重量级产品。在0.1版本发布的时候各个厂商就开始积极响应,Envoy成为Istio默认的数据平面,Linkerd、Nginmesh也放弃了竞争,选择与其集成。

可以把Istio理解为一个微服务的开放平台,它提供了统一的方式去连接、管理和保护微服务。它为微服务之间提供了管理流量、实施访问策略、收集数据等方面的功能,而所有这些功能都不需要修改原有的业务服务就能实现。有了Istio,就几乎可以再需要其他的微服务框架,也不需要自己去实现服务治理,只要客户端和服务端互联互通,把网络层委托给Istio,它就能帮助完成这一系列的功能。下面列举了Istio的一些主要的功能。

  • 对HTTP、gRPC、WebSocket和TCP流量的自动负载均衡。

  • 通过路由规则、重试、故障转移和故障注入等功能实现细粒度的流量控制。

  • 插件式的策略层以及配置API支持访问控制、速率限制和配额请求。

  • 对集群的所有进出流量进行测量、记录并追踪。· 身份验证和授权保证服务间通信的安全。

1.5.4 其他

  1. Conduit

2017年底,Buoyant公司又发布了一款更加轻量级的服务网格产品——Conduit,它基于Rust语言实现。Conduit的整体架构和Istio类似,借鉴了Istio数据平面 + 控制平面的设计。选择Rust编程语言来实现数据平面是为达成Conduit宣称的更轻、更快和超低的资源占用。目前Conduit已经合并入了Linkerd 2.0产品线,它的特点就是支持Kubernetes,并且超级轻量化。

  1. NginMesh

顾名思义,NginMesh是Nginx开发的服务网格产品,2017年9月宣布加入Istio网络工作组,作为Istio平台中的负载平衡和服务代理,并部署为Sidecar代理与Istio集成,以便通过标准、可靠和安全的方式促进服务之间的通信。Nginx提供了一个占用空间小且高性能的代理,具有先进的负载平衡算法、缓存、SSL终止和API网关可扩展性、Lua和nginScript的可写性,以及带有粒度访问控制的各种安全特性。但从目前的情况看,这个项目处于不活跃的状态,应该是趋于流产。

  1. SOFAMesh

SOFAMesh由蚂蚁金服发起,控制面板克隆了Istio的开源库并进行了符合自身要求的改进,MOSN是基于Golang开发的全新数据面板,用以替换Envoy。SOFAMesh除了具有服务网格的基本功能外,还有一些自身的特色:

  • 多协议支持:由于公司内部服务和协议的多样化,因此MOSN实现了多协议支持,同时提供了自定义协议以方便扩展。

  • 性能:为满足大流量的需要,MOSN在I/O、协议、内存、协程、网络处理等多方面进行了优化,保证了生产环境的需求。

  • 安全性:支持mTLS、双向链路加密等。

除上面提到的这些产品外,还有一些相对小众的项目,就不一一介绍了。

1.6 小结

本章主要讲述了服务网格的基本概念。我们简单回溯了服务端架构的发展,阐述了微服务相对单体应用的巨大进步和优势。但同时也了解到,随着服务的拆分和细化,服务间网络通信成为新的痛点,而这也正是服务网格要解决的主要问题和存在的意义。

服务网格是一个负责微服务之间网络通信的基础设施层,提供了管理、控制和监控网络通信的功能,本质上是Sidecar模式的网络拓扑形态。

最后对目前市面上几款主要的服务网格产品进行了简要介绍。第2 章将正式开始介绍本次的主角Istio。