一文深入理解Service Mesh 服务网格

首先,给出Service  Mesh 的定义:

服务网格是一个基础设施层,用于处理服务间通讯。云原生应用有着复杂的服务拓扑,服务网格负责在这些拓扑中实现请求的可靠传递。在实践中,服务网格通常实现为一组轻量级网络代理,它们与应用程序部署在一起,而对应用程序透明。

那么服务网格使用在什么场景下呢? 简单地说来就是为了解决就是微服务场景下的一系列问题。

微服务(Microservices)是一种软件架构风格,它是以专注於单一责任与功能的小型功能区块(Small Building Blocks)为基础,利用模块化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关(Language-Independent /Language agnostic)的API集相互通信。

 

微服务痛点

比如在实现微服务的时候要处理一系列的比较基础和通用的事项,如服务发现,在得到服务器实例列表之后再做负载均衡,为了保护服务器要熔断/重试等等。

这些功能所有的微服务都需要,那怎么办呢?如果将这些功能直接在应用程序里面实现,应用程序里面又加上了大量的非业务相关的代码。很自然的,为了简化开发避免代码重复,我们选择使用类库,如经典的Netflix OSS套件。这样开发人员的重复编码问题就解决了:只需要写少量代码,就可以借助类库实现这些功能。

因为这个原因,最近这些年大家看到Java社区Spring Cloud的普及程度非常快,几乎成为了微服务的代名词。但这一切都完美了吗?

 

侵入式框架的痛点:

以Spring Cloud/Dubbo为代表的传统微服务框架,是以类库的形式存在,通过重用类库来实现功能和避免代码重复。但在以运行时操作系统进程的角度来看,这些类库还是渗透进了打包部署之后的业务应用程序,和业务应用程序运行在同一进程内。所谓”侵入式框架”的称谓由此而来。

而建立在类库基础上的”侵入式框架”,会面临与生俱来的诸多痛点。

 

微服务在面世时,承诺了一个很重要的特性:微服务可以采用最适合的语言来编写。理论上说,不同的团队,不同的微服务,可以根据实际情况选择团队最擅长,或者最适合当前应用的编程语言。

但是,在实践中,这个承诺往往受到极大挑战而沦为空话:微服务的确理论上可以使用不同的语言,但是实际开发时,当需要选择通过框架或者类库来实现代码重用时,就会发现有个绕不开的问题——框架和类库是语言强相关的!

任何框架不可能一开始就完美无缺,所有功能都齐备,没有任何BUG,以至于分发出去之后就再也不需要改动和升级。这种理想状态是不存在的。必然是1.01.22.0慢慢版本升级,功能逐渐增加,BUG逐渐被修复。在这期间,一个接一个新版本陆续发布并分发给使用者。但是,当框架分发给使用者之后,使用者会不会总是保持升级到最新发布的版本?

随着时间的推移会越来越呈现出版本碎片化的趋势。此时,不同版本之间的兼容性问题就会变得非常的复杂,框架的开发人员需要非常小心的维护兼容性,一旦兼容性出现问题,就会严重打击使用者升级的欲望,造成更大的碎片化,恶性循环。

 

解决思路

问题的根源在哪里?

面临的这些问题,这么多艰巨的挑战,和业务应用,或者说服务本身,有直接关系吗?

答案是:没有。这些问题都属于服务间通讯的范围,和应用本身的实现逻辑无关。

我们的目标是什么?

所有的努力,都是为了保证将客户端发出的业务请求,发送到正确的目的地。而”正确”一词,在不同的特性下有不同的语义,如服务发现,负载均衡,灰度,版本控制,蓝绿部署,按照请求内容执行不同的路由策略。服务间通讯的目标,是让请求在满足这些特性要求的前提下,去往请求应该去的目的地服务,而与请求的业务语义无关,和请求的业务处理无关。

服务间通讯的本质是什么?

在整个服务间通讯的处理流程中,无论功能有多复杂,请求本身的业务语义和业务内容(非业务内容可能会有变化如传递特殊的header或者对内容加解密)是不发生变化的。对于服务间通讯,实现的是请求的可靠传递,内容是不变的。

有什么内容是普适的?

前面遇到的这些问题具有高度的普适性:适用于所有的语言、框架、组织,这些问题对于任何一个微服务都是同样存在的。

 

Service Mesh-Istio

所以为了解决以上微服务在实际落地中的种种问题, service mesh就出场了。来看下它是怎么为微服务赋能的:

 

有了这个东西,就真正的把业务和基础通信彻底剥离了,开发者真正关心得是业务,彻彻底底的原生了。把这些业务程序放在云上跑,哈哈,那就是云原生的时代了。

将非业务逻辑的功能实现,从客户端SDK中剥离出来,放到独立的 Proxy 进程中,这是 Service Mesh 在技术实现上走出的第一步,也是至关重要的第一步:因为这一步,实现了业务逻辑非业务逻辑的分离,而且是最彻底的物理分离,哪怕需要为此付出一次远程调用的代价。

而这一步迈出之后,前面就是海阔天空:

  • 业务逻辑和非业务逻辑分离之后,我们就可以将这些非业务逻辑继续下沉
  • 下沉到基础设施,基础设施可以是基于VM的,可以是基于容器和k8s的;也可以是VM和容器混合
  • 基础设施也可以以云的形式提供,可以是公有云、私有云,也可以是混合云、多云;
  • 可以选择云上托管,完全托管也好,部分托管也好,产品形态可以很灵活

总结说,业务逻辑和非业务逻辑的分离:

  • 为下沉到基础设施提供可能
  • 为上云提供可能
  • 为应用轻量化提供可能

 

Service Mesh 的最成功的实践者:Istio

从逻辑上,Istio分为数据平面控制平面两个部分:

  • 数据平面是以 sidecar 方式部署的智能代理,Istio默认集成的是Envoy。数据平面用来控制微服务之间的网络通讯,以及和Mixer模块通信。
  • 控制平面负责管理和配置数据平面,控制数据平面的行为,如代理路由流量,实施策略,收集遥测数据,加密认证等。控制平面分为Pilot、Mixer、Citadel三个组件,后面再详细介绍。

下图是Istio官方文档中的配图,详细描述了数据平面和控制平面的组成、调用关系和主要职责。

关于Istio 的更加详细的解读,可以参考:https://skyao.io/learning-servicemesh/istio/architecture.html ,https://github.com/istio/istio

Service Mesh模式可以归结为以下三点:

  1. 以原生模式开发应用
  2. 以标准模式部署应用:底下发生了什么不关心
  3. 客户端简单发一个请求给服务器端:底下是如何实现的同样不关心,应用只知道请求最终顺利发送完成

Service Mesh产品的存在和具体工作模式,对于运行于其上的云原生应用来说是透明无感知的,但是在运行时这些能力都动态赋能给了应用,从而帮助应用在轻量化的同时依然可以继续提供原有的功能。

Mesh模式不仅仅可以用于服务间通讯,也可以应用于更多的场景:

  • Database mesh:用于数据库访问
  • Message mesh:用于消息系统

云原生指 “原生为云设计”,具体说就是:应用原生被设计为在云上以最佳方式运行,充分发挥云的优势。 

云原生赋能(Cloud Empower)的基本工作原理:

  • 首先要将功能实现从应用中剥离出来:这是应用轻量化的前提和基础
  • 然后在运行时为应用 动态赋能:给应用的赋能方式也要云原生化,要求在运行时动态提供能力,而应用无感知

这些技术之间的关系可以用下面这张图来囊括:

 

  • 为了解决单体的复杂度问题,我们引入微服务架构
  • 为了解决微服务架构下大量应用部署的问题,我们引入容器
  • 为了解决容器的管理和调度问题,我们引入kubernetes
  • 为了解决微服务框架的侵入性问题,我们引入Service Mesh
  • 为了让 Service Mesh 有更好的底层支撑,我们又将 Service Mesh 运行在 k8s上

云原生是一个理想的梦想,要实现他就得有各种方法和手段,简单归纳有以下方面的技术:

未来的发展方向:

如上图所示:

  • 最下方是云,基于k8s和容器打造,提供各种基础能力,这些能力有一部分来自传统中间件的下沉
  • 在云上是 Mesh 层,包含 Service Mesh 以及我们前面提到的各种扩展的Mesh模式,实现通信的标准化
  • 在通过 Mesh 剥离非业务功能并下沉之后,应用实现了轻量化,传统的App和新兴的微服务都可以受益于此
  • 更进一步,轻量化之后的业务应用,其工作负载在瘦身减负之后变得相当的干净,基本只剩业务逻辑,包括传统的App,以Container形式运行的服务和新颖的Function,这些负载在往 Serverless 形态转换时相对要轻松很多

配合 Serverless 技术领域最新的技术潮流和产品发展,Mesh化为现有应用转型为 Serverless 模式提供助力。

 

参考资料:

https://skyao.io/learning-servicemesh/

https://skyao.io/talk/201905-servicemesh-development-trend/

https://skyao.io/talk/201810-ant-finance-service-mesh-practice/

https://skyao.io/talk/201902-cloudnative-freely-talk/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章