本文是服务网格和Istio初识的续篇内容,主要是漫谈(记录)一些关于服务网格、Istio的一些理论及个人认知

为什么还要写这类看似枯燥的文章?我始终认为,学习和实践应用一门新技术之前,应该做好多方调研,全局认知,当前有什么痛点能解决而不是有哪些功能能拿来用等等,到最后不至于仅仅是用了起来而已

1、服务治理的三种形态

服务治理的发展经过了以下三种形态的演进

  • 应用程序中包含治理逻辑(代码自行实现,复用性很低)
  • 治理逻辑独立的代码(sdk方式,提高复用性,但避免不了的是要应用一起打包部署)
  • 治理逻辑独立的进程(sidecar模式,对应用无感知,解耦合)

2、服务网格的特点

  • 基础设施:服务网格是一种处理服务间通信的基础设施层
  • 云原生:服务网格尤其适用于在云原生场景下帮助应用程序在复杂的服务拓扑间可靠地传递请求
  • 网络代理:在实际使用中,服务网格一般是通过一组轻量级网络代理来执行治理逻辑的
  • 对应用透明:轻量网络代理与应用程序部署在一起,但应用感知不到代理的存在,还是使用原来的方式工作

3、网格带来的损耗

传统环境下,服务A到服务B可以直接通过网络(ip或服务名)直连

用了网格后,从A服务到B服务的一个访问必须要经过A服务的Sidecar拦截Outbound流量执行治理动作;再经过B服务的Sidecar拦截Inbound流量,执行治理动作。 这就引入两个问题:

  • 增加了两处延迟和可能的故障点
  • 多出来的这两跳对于访问性能、整体可靠性及整个系统的复杂度都带来了新的挑战

通过保证转发代理的轻量和高性能降低时延影响,尤其是考虑到后端实际使用的应用程序一般比代理更重,叠加代理并不会明显影响应用的访问性能;另外,对于这些高性能的代理,只要消耗足够的资源总能达到期望的性能, 特别是云原生场景下服务的弹性特点使得服务实例的弹性扩展变得非常方便,通过扩展实例数量总是能得到期望的访问性能

因此最终需要决策的是:
是否愿意花费额外的少量资源在这些基础设施上来换取开发、运维的灵活性、业务的非侵入性和扩展性等便利?

4、为什么服务网格选择Istio

  • 控制面设计

Istio作为一种全新的设计,在功能、形态、架构和扩展性上提供了远超服务网格的能力范围。它基于xDS协议提供了一套标准的控制面规范,向数据面传递服务信息和治理规则。Istio的早期版本使用Envoy V1版本的API,即Restful方式,其新版本使用Envoy V2版本的API,即gRPC协议。标准的控制面API解耦了控制面和数据面的绑定。NginxnginMeshF5 NetworksAspen Mesh等多种数据面代理支持Istio的控制面,甚至有些老牌微服务SDK也开始往Istio上集成

  • 数据面设计

Istio的标准数据面Envoy是由Lyft内部于2016年开发的,比Linkerd更早。20169月,Envoy开源并发布了1.0.0版本;20179月,Envoy加入CNCF,成为第2Service Mesh项目;201811月,EnvoyCNCF毕业,这标志着其趋于成熟。从开发语言上看,Envoy是使用C++开发的,其性能和资源占用比用Rust开发的Linkerd Proxy要更好,更能满足服务网格中对透明代理的轻量高性能要求;从能力上看,Envoy提供L3/L4过滤器、HTTP L7过滤器,支持HTTP/2HTTP L7路由及gRPCMongoDBDynamoDB等协议,有服务发现、健康检查、高级LB、前端代理等能力,具有极好的 可观察性、动态配置功能;从架构实现上看,Envoy是一个可高度定制化的程序,通过Filter机制提供了 高度扩展性,还支持热重启,其代码基于模块化编码,易于测试。除了在Istio中应用,Envoy在其他Service Mesh框架中也被广泛应用,渐渐成为Service Mesh的数据平面标准

  • 大厂加持

Istio由谷歌和IBM共同推出,从应用场景的分析规划到本身的定位,从自身架构的设计到与周边生态的结合,都有着比较严密的论证。Istio项目在发起时已经确认了将云原生生态系统中的容器作为核心打包和运行时,将Kubernetes作为管理容器的编排系统,需要一个系统管理在容器 平台上运行的服务之间的交互,包括控制访问、安全、运行数据收集等,而Istio正是为此而生的;另外,Istio成为架构的默认部分,就像容器和Kubernetes已经成为云原生架构的默认部分一样

另外一点,很多的公有云厂商在提供kubernetes容器服务时也内置了Istio功能或者二次开发(包装)了Istio,例如阿里云的asm

5、Istio与kubernetes

IstioKubernetes从设计理念、使用体验、系统架构甚至代码风格等小细节来看,关系都非常紧密。更细粒度的proxy提供更多更细粒度的能力

Istio最大化地利用了Kubernetes这个基础设施,与之叠加在一起形成了一个更强大的用于进行服务运行和治理的基础设施,并提供了更透明的用户体验。

  • 数据面

数据面Sidecar运行在KubernetesPod里,作为一个Proxy和业务容器部署在一起。在服务网格的定义中要求应用程序在运行的时候感知不到Sidecar的存在。而基于Kubernetes的一个Pod多个容器的优秀设计使得部署运维对用户透明,用户甚至感知不到部署Sidecar的过程。用户还是用原有的方式创建负载,通过Istio的自动注入服务,可以自动给指定的负载注入Proxy。如果在另一种环境下部署和使用Proxy,则不会有这样的便利

  • 统一服务发现

Istio的服务发现机制非常完美地基于Kubernetes的域名访问机制构建而成,省去了再搭一个类似Eureka的注册中心的麻烦,更避免了在Kubernetes上运行时服务发现数据不一致的问题

尽管Istio强调自己的可扩展性的重要性在于适配各种不同的平台,也可以对接其他服务发现机制,但在实际场景下,通过深入分析Istio几个版本的代码和设计,便可以发现其重要的能力都是基于Kubernetes进行构建的

  • 基于Kubernetes CRD描述规则

Istio的所有路由规则和控制策略都是通过Kubernetes CRD实现的,因此各种规则策略对应的数据也被存储在kube-apiserver中,不需要另外一个单独的APIServer和后端的配置管理。所以,可以说IstioAPIServer就是KubernetesAPIServer,数据也自然地被存在了对应Kubernetesetcd

Istio非常巧妙地应用了Kubernetes这个好基座,基于Kubernetes的已有能力来构建自身功能。Kubernetes里已经有的,绝不再自己搞一套,避免了数据不一致和用户使用体验的问题

Istio不仅数据面Envoy跑在KubernetesPod里,其控制面也运行在Kubernetes集群中,其控制面组件本身存在的形式也是Kubernetes DeploymentService,基于Kubernetes扩展和构建

最后,看看微服务、容器、KubernetesIstio四者的关系

6、微服务和Istio的选择侧重

微服务是架构风格、方法论,Istio是一套完整的实践

但是,回到我在本文开头提到的一点观念,Istio是用来解决问题的,并不是微服务理论的一种落地,在实际项目中拿着微服务的细节列表来硬套Istio的功能,比如要求Istio治理的服务必须实现微服务的服务注册的一些细节,就明显不太适当

7、Istio的侵入性

从单个应用来看,Sidecar与应用进程的解耦带来的应用完全无侵入、开发语言无关等特点解除了开发语言的约束,从而极大降低了应用开发者的开发成本。这种方式也经常被称为一种应用的基础设施层,类比TCP/IP网络协议栈,应用程序像使用TCP/IP一样使用这个通用代理:TCP/IP负责将字节码可靠地在网络节点间传递,Sidecar则负责将请求可靠地在服务间进行传递。TCP/IP面向的是底层的数据流,Sidecar则可以支持多种高级协议(HTTPgRPCHTTPS等),以及对服务运行时进行高级控制,使服务变得可监控、可管理

从全局来看,在多个服务间有复杂的互相访问时才有服务治理的需求。即我们关注的是这些Sidecar组成的网格,对网格内的服务间访问进行管理,应用还是按照本来的方式进行互相访问,每个应用程序的Inbound流量和Outbound流量都要经过Sidecar代理,并在Sidecar上执行治理动作

Sidecar是网格动作的执行体,全局的管理规则和网格内的元数据维护通过一个统一的控制面实现,只有数据面的Sidecar和控制面有联系,应用感知不到Sidecar,更不会和控制面有任何联系,用户的业务和控制面彻底解耦

8、Istio用在哪

Istio是一个服务治理平台,治理的是服务间的访问,只要有访问就可以治理,不在乎这个服务是不是 所谓的微服务,也不要求跑在其上的代码是微服务化的。单体应用即使不满足微服务的若干哲学,用Istio治理也是完全可以的

9、Istio做了什么

以前后端分离的服务为例
前端 服务的代码中通过域名访问 后端 服务,在两个服务中都不用包含任何服务访问管理的逻辑。Istio在其中都做了什么(可以做些什么)

  • 自动通过服务发现获取服务实例列表,并根据负载均衡策略选择一个服务实例
  • 对服务双方启用双向认证和通道加密
  • 如果某个服务实例连续访问出错,则可以将该实例隔离一段时间,以提高访问质量
  • 设置最大连接数、最大请求数、访问超时等对服务进行保护
  • 限流
  • 对请求进行重试
  • 修改请求中的内容
  • 将一定特征的服务重定向
  • 灰度发布
  • 自动记录服务访问信息
  • 记录调用链,进行分布式追踪
  • 根据访问数据形成完整的应用访问拓扑
  • ……

所有这些功能,都不需要用户修改代码,用户只需在Istio的控制面配置即可,并且动态生效

对业务代码完全没有侵入性

10、用什么姿势接入 Istio

虽然Istio能解决那么多的问题,但是引入Istio并不是没有代价的。最大的问题是Istio的复杂性,强大的功能也意味着Istio的概念和组件非常多,要想理解和掌握Istio,并成功在生产环境中部署需要非常详细的规划。一般情况下,集群管理团队需要对kubernetes非常熟悉,了解常用的使用模式,然后采用逐步演进的方式把Istio的功能分批掌控下来

  • 第一步,自然是在测试环境搭建一套Istio的集群,理解所有的核心概念和组件。了解Istio提供的接口和资源,知道它们的用处,思考如何应用到自己的场景中,然后是熟悉Istio的源代码,跟进社区的issues,了解目前还存在的issuesbug,思考如何规避或者修复。这一步是基础,需要积累到Istio安装部署、核心概念、功能和缺陷相关的知识,为后面做好准备

  • 第二步,可以考虑接入Istio的观察性功能,包括loggingtracingmetrics数据。应用部署到集群中,选择性地(一般是流量比较小,影响范围不大的应用)为一些应用开启Istio自动注入功能,接管应用的流量,并安装prometheuszipkin等监控组件,收集系统所有的监控数据。这一步可以试探性地了解 Istio对应用的性能影响,同时建立服务的性能测试基准,发现服务的性能瓶颈,帮助快速定位应用可能出现的问题。此时,这些功能可以是对应用开发者透明的,只需要集群管理员感知,这样可以减少可能带来的风险

  • 第三步,为应用配置timeout超时参数、自动重试、熔断和降级等功能,增加服务的容错性。这样可以避免某些应用错误进行这些配置导致问题的出现,这一步完成后需要通知所有的应用开发者删除掉在应用代码中对应的处理逻辑。这一步需要开发者和集群管理员同时参与

  • 第四步,和ingresshelm、应用上架等相关组件和流程对接,使用Istio接管应用的升级发布流程。让开发者可以配置应用灰度发布升级的策略,支持应用的蓝绿发布、金丝雀发布以及AB测试

  • 第五步,接入安全功能。配置应用的TLS互信,添加RBAC授权,设置应用的流量限制,提升整个集群的安全性。因为安全的问题配置比较繁琐,而且优先级一般会比功能性相关的特性要低,所以这里放在了最后

当然这个步骤只是一个参考,需要根据自己的情况、人力、时间和节奏来调整,找到适合的方案

11、Istio不是银弹

Istio的架构在数据中心和集群管理中非常常见,每个agent分布在各个节点上(可以是服务器、虚拟机、pod、容器)负责接收指令并执行,以及汇报信息;控制中心负责汇聚整个集群的信息,并提供API让用户对集群进行管理。kubernetes也是类似的架构,SDN(Software Defined Network)也是如此。相信以后会有更多类似架构的出现,这是因为数据中心要管理的节点越来越多,我们需要把任务执行分布到各节点(agent负责的功能),同时也需要对整个集群进行管理和控制(control plane的功能),完全去中心化的架构是无法满足后面这个要求的

Istio的出现为负责的微服务架构减轻了很多的负担,开发者不用关心服务调用的超时、重试、rate limit的实现,服务之间的安全、授权也自动得到了保证;集群管理员也能够很方便地发布应用(AB 测试和灰度发布),并且能清楚看到整个集群的运行情况

但是这并不表明有了Istio就可以高枕无忧了,Istio只是把原来分散在应用内部的复杂性统一抽象出来放到了统一的地方,并没有让原来的复杂消失不见。因此我们需要维护Istio整个集群,而Istio的架构比较复杂,尤其是它一般还需要架在kubernetes之上,这两个系统都比较复杂,而且它们的稳定性和性能会影响到整个集群。因此再采用Isito之前,必须做好清楚的规划,权衡它带来的好处是否远大于额外维护它的花费,需要有相关的人才对整个网络、kubernetesIstio都比较了解才行