近几年我一直从事于微服务系统的设计以及实现方面的工作,属于微服务架构一线实践者。之前做过一些单体系统的微服务改造,在微服务拆分、治理等方面都有一定的经验。

本人比较特殊一点的经历是既做过 IT 领域的微服务,也做过 CT(通讯领域)的微服务,微服务架构在这两个领域的具体形态和要求是不太一样的,但其中一些思想是互通且是很有借鉴意义的。今天主要介绍一下关于微服务的最新发展动态,以及最近谷歌推出的 Istio平台架构。

今天介绍的主题包含:服务治理、服务网格、Istio架构,以及 Istio 相应的系统组成。

一、分布式计算的八个谬论

1.png

彼得多维奇多年前提出的分布式计算的八个谬论,对于开发人员来说他们往往会忽视这八条。这八条基本上都和网络相关,例如在发起一个网络请求时,会不断地做一些尝试等待,来保障消息投递的有效性。

微服务是一个更为复杂的分布式系统,之前 SOA 或者B/S,CS 架构,它的颗粒度会更粗一点,但是如果采用微服务,它的颗粒度是更细的。在马丁·富勒博客《微服务的先决条件是什么》一文中提到一条,你必须要成为“高个子”,想成为“高个子”其实并不简单,很多公司,它们都是为了成为“高个子”,做了很多框架、平台。

二、服务治理

1、微服务治理的技术点

 

2.png

要成为“高个子”需要对微服务进行哪些改造,这里是相关服务治理的技术点,其中只是一部分,和服务网格比较相关的技术点,包含服务发现、负载均衡、请求路由、认证与授权、可观测性,还有健康检查、容错等。目前主流的解决方案有众所周知的 Spring Cloud, Dubbo 等,这些都是提供库来把服务治理相关的内容打包,供具体的业务去调用。

2、库或框架的问题

但是库和框架会存在一些问题:

** 1、学习成本。**多一个库对于开发人员而言,意味着要多学一些东西,并且在业务开发过程中,还会受到库或者框架的制约。

2、对业务代码的侵入性。例如用 Spring Cloud 会在代码里面加很多额外的内容,比如每个请求里面加一个注解来表达想引用服务治理的某些功能。

3、基础库的维护、升级和下线。如果是以库的方式来提升到服务里面,库的维护、升级、下线就会造成整个服务的维护、升级、下线。

4、不同语言和技术栈。在提出微服务概念时,它的一个重要好处就是可以使用不同的技术栈来开发微服务,但如果受到框架制约,只能用这个语言,这是我们比较头痛的事情,无法发挥微服务跨语言的能力。

这些问题其实是有严重程度的,从上往下越来越让开发人员觉得不舒服。理想中的服务治理方案是什么?可以先畅想一下,整个服务治理相关的东西,应该是和业务逻辑完全隔离的,并且服务和服务之间的交互是不会考虑服务治理这块内容,最好对于业务开发来说是不可见的。

这时候怎么去做呢?就引出了容器经典部署模式——Sidecar。

3、Sidecar模式

4.png

Sidecar 模式通常是和容器一起使用,如果不和容器一起使用也没关系,那就是两个独立的进程,如果和容器使用的话,就基于容器为单位。Sidecar模式是物理隔离的,并且与语言无关。因为是两个独立的东西,可以独立发布,和微服务理念一样。另外它们是部署在同一个 Host 上面,所以资源之间可以做到相互访问,并且因为在一起所以通信延迟也不会太明显。和业务无关的功能都可以放上去,形成多个 Sidecar。今天 Sidecar 主要是把一些服务治理相关的东西放在里面,做软件设计上的思想就是分离关注点。

 

5.png

基于 Sidecar 模式做服务治理,之后形成连接的具体状况,如图,对于服务A来说,服务A是不知道和 Sidecar 进行通信,服务A还是向服务B发消息,照常调用通信接口,但是消息可能会被 Sidecar 捕获到,然后通过Sidecar 进行转发。

三、服务网格

8.png

从整个系统来看,如果以 Sidecar 方式来部署服务治理以及服务的话,最终形成的系统如图。能看到通过 Sidecar 进行相互连接,形成一个网络,这也是服务网格名字的由来。每一个节点上面都相当于具体的网格,和多年之前提的网格计算有点类似。

服务网格如果站在更抽象的层次来看是什么样子?把服务治理相关的东西抽象来看的话,服务网格也算是一种基础设施,它和具体的业务无关。不管是 PaaS 的发展,还是服务网格的发展,都是将与业务无关的内容的共同点提取出来,然后形成独立的一套平台或者方案。另外,服务网格之间要形成可靠传递,刚才提到的重试等功能都应该具备。

服务网格是轻量级的网络代理,不能太重,不能喧兵夺主,服务才是整个系统中最重要的东西,而这些基础设施并不应该取代服务最重要的价值地位。

更关键的一点是要对应用程序透明。对于服务而言是看不到 Sidecar、看不到代理的,服务如果要发消息出去,它知道是发给这个代理的,那对于我们的业务来说同样也是一种污染。服务网格最终不再强调代理作为单独的组件,不再孤立的来看代理,而是从全局的角度来看待代理所形成的网络。

1、服务网格定义

服务网格的定义是 Willian Morgan 提出来的,他是最早做服务网格的人。如图,文字加粗的是服务网格一些关键技术点。右边图是最新发展的服务网格,在最上层还会加一个控制面板,通过控制面板来管理这些代理,这些代理是需要被管理的。如果我们的运维环境没有控制面板,可能就没办法运维了。

2、服务网格的基本构成

9.png

服务网格必须要具备数据面板控制面板,如果新开发一个服务网格只有数据面板,它肯定不是一个完整的服务网格。

数据面板是用来接收系统中的每一个包或者请求,提供服务发现、健康检查等服务治理相关的,都是由数据面板来完成。数据面板的一些典型代表有 LinkedEnvoy、和 Nginx 公司开发的 Nginmesh,以及硬件服务的代理厂商F5开发的 Aspen Mesh。目前主要的、成熟的是 Linked 和 Envoy,这两者都在生产环境上面真实部署过,实战过。而且Linked的采用会更广泛一些,因为它出现的时间最早。

对于控制面板来说,是为了在网格中运营的数据面板提供策略和配置,负责一些管理工作,它不会接收系统中的任何包或者请求。这里的包和请求应该是业务相关的包和请求,和具体的业务是完全没关系的。本来做微服务应该做去中心化的事情,但是又有一个控制点在那里,要强调的是那个控制点和具体的业务没什么关系。控制面板的典型代表,包括 Istio、ConduitNleson、SmartStack,目前最新的是 Istio 和 Conduit。

3、数据面板对比

10.png

左边是 Linked(Scala编写),右边是 Envoy(C++编写),它们最大的区别就是实现语言的区别。同时,Linkerd 和 Envoy 都是在生产环境已经验证过的两个系统,功能上都没问题,都比较强大,它们唯一的区别就是对于硬件资源的要求,Linked 是非常高的,它可能就会造成喧兵夺主的感觉,所以目前 Envoy 在这块是比较火的,Envoy 是由C++开发的。

4

控制面板对比

11.png

两个最新的控制面板,一个是 Istio,是由 Google、IBM、Lyft 开发的,而 Conduit 是由 Buoyant 公司开发的,跟刚才所说的性能不太好的数据面板Linkerd是同一家公司,Buoyant 在 Linkerd 之后又重新开发了 Conduit,专门来解决性能上的问题,所以在性能上面来看,Conduit 的性能指标已经出来了,就是微秒级,并且是P99延迟。

但是 Istio 的性能指标现在还没出来,还在功能开发阶段。因为 Istio 需要实现的功能比较多,要支持各种各样的平台和过滤,Istio 整个架构非常灵活,所以 Istio 整个量级是比较重量的,但是 Conduit 只支持 K8S,Conduit 的原则是怎么快怎么来。

从编程语言上来说,控制面板 Istio 和 Conduit 都是使用Go语言,但是在数据面板上 Istio 是使用C++,Conduit 使用 Rust,可以看出来这两个语言都是那种比较高效的,在数据面板上面必须要使用高效的语言来完成。

四、Istio架构

12.png

一句话定义 Istio:一个用来连接、管理和保护微服务的开放平台。刚才也说了 Istio 是 Google 开发的,所以 Istio 今后的趋势肯定是会越来越火的,并且目前 K8S 已经把它集成到里面了,做成一个可选的组件。

对于连接而言,Istio 它主要包含弹性、服务发现、负载均衡,管理是流量控制、策略增强,监控也有,并且安全这块 Istio 也是有考虑,Istio 是端到端的身份验证和授权,等一下会详细的介绍。

Istio的****关键特性****:

13.png

 

14.png

1、智能路由和负载均衡。这里的智能路由和负载均衡是属于比较高级的,不是像传统简单的随机负载均衡,而是可以基于一些数据包内部的内容来进行负载均衡。

2、跨语言和平台的弹性。对于平台来说 Istio 是支持各种各样的平台,并且能支持A/B测试,金丝雀发布,并使用蓝绿部署运维上的一些高级功能。

3、全面策略执行。Istio 有一个组件是专门负责保障策略能够通过一个组件下发到具体的数据面板。

4、遥测和上报。即具体的测量以及流量的监控等。

![16.png](http://upload-images.jianshu.io/upload_images/1322591-5304690d2bffc6de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这个就是 Istio 整个的系统架构,如图,上面是控制面板,下面是很多数据 Envoy,很多个代理,形成一个数据面板。后面我们会对单个进行详细介绍。

image.gif

这是在 K8S 下面 Istio 部署的示意图,可以看到它们之间最关键的东西是所有服务和组件都会有一个代理,这代理是必备的,包括控制面板都会有代理。没有画的有两个东西,一个是 Ingress,一个是初始化器,初始化器主要是做代理注入。它们之间相互的交互都是通过加密,由TLS协议来完成。

五、Istio组件

1、数据面板Envoy

17.png

介绍一下 Istio 的核心组件,首先是 Istio 的数据面板 Envoy。

Envoy 的目标是透明地处理集群内服务间、从服务到外部服务之间的出入口流量。Envoy 是用C++编写的,高并行、非阻塞。并且是可装卸的L3/4过滤器,以及L7的过滤器,最终会形成一个过滤链来对流量进行管理或者控制,Envoy 是通过 xDS 动态配置来进行接口提供。

下面就是一些固有的功能,服务发现、健康检查。Envoy 的健康检查也做的颗粒度比较细,包含主动健康检查和被动健康检查。主动健康检查像常规的健康检查,主动地发一个健康检查的接口调用请求,查询一下。被动的是通过对其他服务的一些请求,从一些返回值进行健康检查。当然还包含高级的负载均衡,监控、跟踪这些功能。

Envoy最关键的三个点:

  • 高性能。一直在强调的是数据面板必须要高性能,因为是要和业务服务部署在一起的。
  • 可扩展。
  • 可配置。具有动态配置的特性。

Envoy 是如何做到高性能的?

 

18.png

Envoy 的线程模型分为三类线程,如果做过C++开发,这种单进程多线程的架构是很常见的。Envoy 分为主线程、工作线程、文件刷新线程,其中主线程就是负责工作线程和文件刷新线程的管理和调度。而工作线程主要负责监听、过滤和转发,工作线程里面会包含一个监听器,如果收到一个请求之后会通过刚才所介绍的过滤链来进行数据过滤。前面两个都是非阻塞的,唯一一个阻塞的是这种 IO 操作的,会不断地把内存里面一些缓存进行落盘。

19.png

服务网格所强调的另外一个功能,是动态配置不用重启,实际上是重启的,它会启动一个新的进程,然后在这进程之上进行新的策略,还有一些初始化,这时候再请求监听,之前那个进程的 socket 副本。当老的关闭链接以及退出之后,它才会接收新的,这时候就实现了对用户没有感知的重启。

这就是它的 xDS,如图,可以看到它的密度是非常细的,

20.png

  • 终端发现服务(EDS),实际上就是服务的发现服务;
  • 集群发现服务(CDS)是为了发现集群;
  • 路由发现服务(RDS)是为了对路由进行一些处理;
  • 监听器(LDS)来动态地添加、更新、删除监听器,包括过滤链的一些管理、维护。
  • 另外还有刚才说到的健康检查(HDS),
  • 还有聚合(ADS)是对于监控指标进行聚合的接口;
  • 另外一个密钥发现(KDS)是和安全相关的。

首先,如果来了一个请求,会到刚才所说的工作线程里面去,工作线程会有监听器,收到之后进行一些处理,然后要往外发,这时会调用路由的发现功能,然后再找到相应的集群,再通过这个集群找到相应的服务,一层一层的往下面调用。

2、控制面板Pilot

接下来介绍的是控制面板的三大组件,第一个就是 Pilot。

22.png

Pilot 是运行时的代理配置,刚才所说的 xDS,就是用 Pilot 来进行调用,负责把相应的一些策略,失败恢复的特性派发下去。Pilot 是负责管理所有的这些代理,代理和管理就通过 Pilot 来完成,是平台无关的一个拓扑模型。目前主要支持的是 K8S。

23.png

Pilot 是一层抽象的独立于底层平台的模型,因为这里有个代理,对于多平台或多样性的管理架构,即适配器的架构。平台特定的适配器负责适当填充这些规范,要通过具体平台的适配器形成一些规范,和通用的模型结合,生成必须要往 Envoy 下发的数据,并且配置、推送都是由 Pilot 来完成的。

![25.png](http://upload-images.jianshu.io/upload_images/1322591-76906702dce62460.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

Pilot 的整个服务发现和负载均衡,如图,Pilot 是Kubernetes DNS提供的域名进行访问,首先调用 Service B 的url,这时候 Envoy 会进行截获并处理,处理完之后会找到相应的负载均衡的池子挑选一个进行流量下发。Pilot 目前支持的这种负载均衡的方法,规划了很多种。但目前只实现了三种,前两种还是随机和轮循,多了一个最小请求的负载均衡算法。它能找到这些 Pilot 里面哪个被调用的最少,然后进行调用。

Pilot 的一些规则配置,可以看到基本是负责规则的管理以及下发。

  • 路由规则。
  • 目的地策略。主要包含负载均衡的算法,以及对于负载均衡算法抽象的策略预演。
  • 出站规则。

把这些规则分了三类,好处是对这三类都会生成一些模板。

image.gif

流量的拆分可以看到是基于标签的流量拆分,这里配置的如版本,环境,环境类型,它根据这个规则来进行流量的派发。比如说99%都发给之前版本,新版本先1%先测一下,类似于A/B测试。

另外一个比较高级的是基于内容,因为它是L7的这种过滤,可以基于内容来过滤,并且支持表达式,这种将iPhone的流量全部导到新的服务里面去,并且有标签,版本必须得是金丝雀版本。

3、混合器Mixer

28.png

Mixer 是在应用代码和基础架构之间提供一个中间层,来隔离 Enovy 和后台基础设施,这里的后台是指 Promethus,ELK 这些。

Mixer 有三个核心特性:

  • 先决条件检查。负责白名单以及 ACL检测;
  • 配额管理。负责这种使用频率上的控制;
  • 遥测报告。

总共分为两类,在生成配置模板的时候它是有两类的,第一类就是负责检查check,第二类就是负责报告reporter。

Mixer 是采用通用的插件模型以实现高扩展性,插件被称为适配器。运维人员下发一些配置到这里面,这些模板又是由模板开发人员进行开发的,Istio提供了很多通用性的模板,上面简单地改造一下就能做出一个模板来。适配器也有很多种,各种后台、平台的都有。

Mixer 是抽象了不同后端的策略,遥测系统的细节,它就对这两个东西进行了抽象,形成了一套抽象的东西。

 

29.png

刚才介绍过适配器,再来介绍一下处理器,它是配置好的适配器,由运维人员进行配置,之后形成最终的处理器,负责真正往后台发东西。

它封装了与后端接口所需的逻辑,指定了配置规格,以及适配器。如果要在后台进行消息交互的话,所需要的操作参数在这里也会定义。而右边就是两个模板,第一个模板是 Prometheus,它是一个处理器,下面是它的一些指标。另外一个是白名单检查的模板,提供URL,以及它请求的接口返回值。

刚才介绍了整个通路是怎么打通的,包括适配器和处理器都是为了干这个事情,这个通路怎么建立?接下来要介绍的是这个参数怎么生成,它是请求属性到一个模板的映射结果。

Mixer 会收到 Envoy 发过来的很多属性(请求),请求里面包含的数据都称之为属性。通过它的模板来生成相应的具体参数,这边也是刚才两个例子里面对应的模板。上面是度量指标采集用的,下面是白名单。

32.png

33.png

这里有个遥测报告的示例,当收到一个请求之后会发生什么。它会以属性的形式,这边有个 Zipk,就直接上报了,这是因为 Envoy 原生的就支持Zipk。Envoy 支持后端监控的东西,就是 Zipk,所以它可以直接发给它。其他的需要通过 Mixer 来进行转发。

 

![35.png](http://upload-images.jianshu.io/upload_images/1322591-1a4344186ac2203f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

首先它收到这个属性之后,会把这个属性生成具体的实例。根据运维人员提供的配置,Mixer 将生成的数据分发到一组适配器,适配器要根据运维人员的配置来生成具体的数据,之后就可以把刚才所生成的实例往下发了。发到后端后可以进行进一步的分析和处理。

4、密钥管理

38.png

最后要介绍的就是安全相关的,Certificate Authority 这块,这是整个密钥管理的示意图,可以看到服务和 Envoy 是通过 TCP 进行交互的,但是Envoy 和 Envoy 之间是通过 MTIS 进行加密,是双向的 TIS 加密。它的好处是,会在内部的每一个服务节点之间做加密,当然这是可选的,根据性能的需求来进行选择。

密钥管理分为四个步骤,这四步就是四个特性,第一,通过服务帐户生成的密钥和证书,然后再将密钥和证书部署到 Envoy上,它还支持周期性的对这证书进行更新,另外还支持撤销的功能。

这是它的两种部署方式,一种 K8S 的部署方式,另外如果是虚拟机,它会单独有一个节点代理,通过节点代理来发出签名请求给CA,CA再生成密钥和证书给代理,代理再来负责部署到 Envoy上。

具体的运行时它们都有各自的证书,开始进行双向的 TIS,这时候会到名字信息里面去查询,后端有没有权限访问,如果有的话就往下,没有就结束了。

第三步,如果收到一个客户端的请求,会去 Mixer 里面判断一下,它是白名单上的一个判断或者是不是黑名单上的一个判断,会影响“握手”的成功与否。最终它们就形成了安全交互的通道。

45.png

谢谢大家,今天我们主要给大家介绍一下 Istio 是什么,大家有初步的认识,并且对它里面比较关键的技术进行了介绍。

六、Q&A

Q1:现在有这么个项目,您怎么看像这种项目的发展?第二个问题,你们中心现在在做,您也分析的挺深入,未来是什么计划,会和paas有融合吗?

A1:先回答第一个问题,我们可以看到不管是数据面板还是控制面板都会有很多个,但是控制面板,谷歌和IBM,刚才所说的是由三个公司来开发的,谷歌、IBM,还有Lyft,那个公司类似于滴滴那种业务的公司,它们负责Envoy的开发,数据面板是它们公司来负责。我们可以看出来它们是有点分离的感觉,对于谷歌或者IBM来说它们更关注的是控制面板,并且在控制面板和数据面板之间的接口设计的非常好,设计了一套通用的接口。它们最终是分为两个方向发展,但是都可以通过同一套标准集成起来。

第二个问题,首先公司内部都在采用微服务,对于Istio至少要到1.0之后才会在内部环境使用,如果没问题才会逐渐往真正的对外业务使用它,包含通讯里面都可能会用它。但是对于CT领域来说的话,用这个可能代价就需要好好地评估一下了。因为性能上的问题,它毕竟还是多了一跳。如果两个服务之间的交互就相当于多了两跳,对于通信这种实时性要求非常高的领域可能会存在问题。我们也会开发自己的一套侵入式框架,可以参考Envoy的实现。

Q2:我们现在游戏项目里面刚好也用到它。但是它有个问题,用的感觉有点大材小用,我们用它做调用链关系分析,因为我们集群开发很多游戏,每个游戏有个pilot,但是如果出了问题我不知道,那它里面的一个插片自动生成,它只能识别K8集群里面pod。如果我们想用它把K8S的集群和非K8S的集群调用,并且全部进行连接起来的话,它是否支持?

A2:我觉得它现在由于所处在初级阶段所以暂时不支持是正常的,但它后续的发展肯定会支持,因为它们整个设计的目标就是为了达到这种服务粒度,而不仅限于K8S pod这种管理粒度。

Q3:我有一个关于sidecar的问题,如果作为一个客户端去请求的时候应该要引流引到sidecar上面,它引流是怎么引的?如果直接转过去的话又怎么去识别目标的服务到底是什么样的?它调用的是什么服务,后端可以路由到几个上?

A3:这个信息都是由刚才所说的pilot来负责收集,它会把这些信息下发到Envoy上,所以它在做路由算法的时候会访问,来获取它可以访问到哪些服务,它会把服务的信息找到,包括它能访问的服务池包含哪些内容,然后再通过策略进行控制。

它是会反向再去K8S里面找到的,并不是完全Envoy自己来负责,这些信息都是由pilot来给它,拿到这些信息再做处理,最终还是会和平台结合到一起。它有一个假设,所有的平台都会实现这种服务发现的接口,并且会从服务发现的接口拿到一些必要的信息,包含你刚才说的,会转成相应的IP。