谈ServiceMesh微服务治理在云原生解决方案中作用
作者:人月神话,新浪博客同名
简介:多年SOA规划建设,私有云PaaS平台架构设计经验,长期从事一线项目实践
今天谈下基于ServiceMesh服务网格下的微服务治理在整个云原生解决方案中的关键作用。在前面谈云原生解决方案的时候,我们重点都在谈微服务+DevOps+容器云,但是毕竟少谈到ServiceMesh服务网格。
要明白在单体拆分为微服务后,各个微服务间通过Http Rest API接口进行交互,那么这些接口的统一管控和治理就非常重要。因此微服务治理也是整个大应用架构集成设计中的一个关键内容。如果微服务间的接口没有统一管控起来,实现统一的安全,日志,流控,负载均衡和路由,那么微服务又将重回到传统IT架构中复杂而又难以管理的局面。微服务治理的几种方式
对于微服务架构下的服务治理,实际上我们看到三种典型方式。通过服务注册中心+配套组件通过API网关来实现统一的注册,安全,限流和日志管理通过类似Istio的ServiceMesh方案来实现服务治理
在前面就谈到过,对于服务注册中心方式,实际上服务治理能力偏弱,一般只实现服务注册和发现,负载均衡,而对于限流熔断,日志管理,安全等往往都还需要结合其他技术组件一起来完成。但是服务注册中心最大好处就是去中心化架构。
而对于API网关前面也讲过,可以统一实现代理路由,服务注册,安全,限流和日志管理,但是API网关本质可以理解为类似ESB总线产品的一种轻量实现,因此通过API网关集成后整个架构变成了中心化架构,API网关如果存在故障异常,那么导致整个微服务架构体系不可用。
那么是否存在同时兼顾前面两者的解决方案?
实际上ServiceMesh的思路正好是兼顾两者,通过在微服务中注入Sidecar方式来实现微服务治理管控,同时又实现了数据流和控制流的分离,满足了去中心化架构要求。
在前面一篇文章我谈到过去中心化的API网关,实际和ServiceMesh思路类似。
从API网关的去中心化到ServiceMesh分布式服务治理
这里重点仍然是控制流和数据流分离,类似ServiceMesh架构中的控制面和数据面,通过下发SDK包到微服务模块的方式来实现整体的服务注册调用,限流熔断和日志管理等能力。
而到了ServiceMesh下解决方案,则是通过数据平面和控制平面,通过在微服务模块中下发Sidecar的方式来实现控制流和数据流的分离。同时实现了我们需要的服务注册发现,安全,日志,流控等各种微服务治理能力。
服务网格是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但对应用程序透明。采用类似Istio微服务治理的好处在哪里?
在我前面文章里面就提到过,我们通过将单体应用转换为微服务架构,实现了单体应用本身进一步的业务组件和功能间的解耦。同时我们在谈技术中台的时候又谈到,通过将共性技术能力下沉,来实现微服务和底层技术平台间的解耦。
单个微服务和技术框架解耦
那么最好剩下一个问题,即微服务开发技术框架?
比如前面我们谈到的基于SpringCLoud的微服务开发框架,可以启用Eureka+Feign+Ribbon来完成微服务模块间的内部集成,API接口注册和调用。你也可以看到采用SpringCLoud全家桶来满足整体的微服务治理和管控需求。
但是实际的问题在哪里?
即你开发的单个微服务模块实际上和SpingCLoud开发框架又变成了紧耦合的关系。即微服务模块本身是依赖这个技术框架的,而这个技术框架本身也可能很重。
比如我们常说的声明式调用,在客户端的一些负载均衡,你脱离了这个技术开发框架,脱离了Feign和Ribbon组件往往就无法正常运行。
包括我们看到类似Consul服务注册发现和服务治理,也是需要在微服务中下沉Proxy代理才能够完成。而这些都加大了单个微服务模块的技术依赖性。
简单来说,我们实际是希望单个微服务更加纯粹。
即就是开发一个独立的微服务模块,能够暴露Http Rest API接口服务即可。
涉及到的服务注册发现,负载均衡,限流,安全,日志等各种微服务治理能力最好都不用对微服务模块的开发有任何的侵入。同时我们在开发微服务模块的时候也不用去关心这些内容。也就是我们说的服务治理管控能力对单个微服务完全透明。
单个微服务支持多开发语言
其次,我们希望对于单个微服务的开发支持多种开发语言。比如对于前端你可能采用Python语言来实现,对于后端可能又采用的go语言或Nodejs来实现。
而我们实际上又期望通过一套微服务治理框架来满足对现有微服务的治理管控能力。如果你采用类似SpringCLoud的解决方案显然是无法满足以上需求。
对服务注册中心和API网关两种类型的兼顾
在前面的文章我谈到过,如果一个大应用下的多个微服务模块间有API接口交互,那么直接通过服务注册中心来完成服务治理管控即可。
但是如果存在以下几个场景,我们可以采用API网关对API接口服务的安全,日志,限流熔断方面有强管控需求需要暴露API接口服务给外部应用或APP使用存在跨多个团队间的协同的时候
因此,在一个微服务架构体系下往往就存在,内部API接口走服务注册中心,外部的以下API接口发布协同通过API网关管理。如下图:
这个时候你会发现,对于负载均衡,限流熔断,服务注册发现往往存在独立的两套,而且两套之间还无法互通。其次对于API网关有的日志审计能力,往往对于内部注册中心和点对点调用产生的日志又服务进行记录和统一管理。
也就是说,在一个大应用同时使用了服务注册中心,API网关的时候。我们整个微服务治理变得反而更加复杂了。也正是这个原因,你可能会要求所有的API接口服务全部注册到API网关进行统一管理,但是这本身又带来了中心化架构的问题和更多的性能消耗。
也正是如此,我们更加希望一套微服务治理方案来解决问题。
在这种方式下进行统一后,唯一还需要考虑的就是,对于对外API接口服务的统一代理出口问题。这个即可以使用控制中心的Gateway网关出口,也可以直接将需要对外暴露的接口服务接入到类似Ngnix即可。
为何通过ServiceMesh来实现微服务治理
根据上面可以看到,我们实际上目标是希望有一个去中心化的微服务治理框架,去中心化的好处就是可以完全避免中心化节点本身的冗余扩展和性能损耗问题,方便扩展。
其次,我们又希望在去中心化后实现我们期望的所有场景安全,日志,限流熔断,服务注册发现等微服务治理管控能力。而ServiceMesh架构刚好解决了这个问题。对于这个问题的解决采用ServiceMesh架构方式带来的好处是:去中心化架构,控制流和数据流分析,高性能对微服务模块开发无任何侵入完全透明实现完整的安全,日志,限流熔断,注册发现管控能力异构环境,多语言实现统一治理管控
而以上正好是我们需要的内容。比如整个Istio开源实现,整体内部机制仍然会很复杂,但是这些复杂性实际对我们开发微服务的开发人员不可见,开发人员也完全不用关心。也就是我们常说的,对于微服务开发人员,可以真正专注业务功能的开发,而不需要关心微服务治理如何实现。和Kurbernetes容器云集成
如果这个Sidecar边车代理需要我们人工去注入微服务,并进行相关配置和部署。那么说明整个ServiceMesh架构并没有实现和微服务之间的彻底解耦和透明化。
而类似Istio解决方案,可以看到,其天生就实现了和类似Kurbernetes, Mesos容器云PaaS平台的集成能力。也就是说Istio本身就依托于一个Kurbernetes集群而存在,可以实现和集群之间的无缝集成和动态扩展能力。
也就是我们常说的,在通过Kurbernetes进行容器部署的时候,我们可以将微服务容器和Sidecar两个容器打包到一个Pod中进行部署和管理,这个过程本身是自动的,不需要任何人工去处理和干预,对开发人员来说也完全透明。
我们可以摘录《云原生服务网格Istio》内容来理解各组件的功能及相互之间的协作方式。
1. 自动注入:在创建应用程序时自动注入 Sidecar代理Envoy程序。在 Kubernetes中创建 Pod时,Kube-apiserver调用控制面组件的 Sidecar-Injector服务,自动修改应用程序的描述信息并注入Sidecar。在 真正创建Pod时,在创建业务容器的Pod中同时创建Sidecar容器。
2. 流量拦截:在 Pod 初始化时设置 iptables 规则,基于配置的iptables规则拦截业务容器的Inbound流量和Outbound流量到Sidecar上。而应用程序感知不到Sidecar的存在,还以原本的方式 进行互相访问。流出frontend服务的流量会被 frontend服务侧的 Envoy拦截,而当流量到达forecast容器时,Inbound流量被forecast 服务侧的Envoy拦截。
3. 服务发现:服务发起方的 Envoy 调用控制面组件 Pilot 的服务发现接口获取目标服务的实例列表。frontend 服务侧的 Envoy 通过 Pilot 的服务发现接口得到forecast服务各个实例的地址。
4. 负载均衡:服务发起方的Envoy根据配置的负载均衡策略选择服务实例,并连接对应的实例地址。上图中,数据面的各个Envoy从Pilot中获取forecast服务的负载均衡配置,并执行负载均衡动作。
5. 流量治理:Envoy 从 Pilot 中获取配置的流量规则,在拦截到 Inbound 流量和Outbound 流量时执行治理逻辑。上图中, frontend 服务侧的 Envoy 从 Pilot 中获取流量治理规则,并根据该流量治理规则将不同特征的流量分发到forecast服务的v1或v2版本。
6. 访问安全:在服务间访问时通过双方的Envoy进行双向认证和通道加密,并基于服务的身份进行授权管理。上图中,Pilot下发安全相关配置,在frontend服务和forecast服务的Envoy上自动加载证书和密钥来实现双向认证,其中的证书和密钥由另一个管理面组件 Citadel维护。
7. 服务监测:在服务间通信时,通信双方的Envoy都会连接管理面组件Mixer上报访问数据,并通过Mixer将数据转发给对应的监控后端。上图中,frontend服务对forecast服务的访问监控指标、日志和调用链都可以通过这种方式收集到对应的监控后端。
8. 策略执行:在进行服务访问时,通过Mixer连接后端服务来控制服务间的访问,判断对访问是放行还是拒绝。上图中,Mixer 后端可以对接一个限流服务对从frontend服务到forecast服务的访问进行速率控制等操作。
9. 外部访问:在网格的入口处有一个Envoy扮演入口网关的角 色。上图中,外部服务通过Gateway访问入口服务 frontend,对 frontend服务的负载均衡和一些流量治理策略都在这个Gateway上执行。
从上面可以看到:
当Kurbernetes完成一个微服务的部署或动态扩展后,我们会自动将Sidecar注入到同一个Pod中形成边车模式,实现统一的代理,路由和负载均衡,同时实现对消息流的拦截能力。
在微服务模块部署完成后,首先是模块注册到Kurbernetes集群,然后集群将注册信息推送到Pilot组件,Pilot组件再将服务注册信息,相关配置信息通过xDS接口推送到Novy组件。
具体实现过程可以参考下图:
在这个过程中我们看到,微服务的部署和资源动态扩展,服务的注册发现,注册信息的注入下发等所有操作完全不需要人工干预,对微服务开发人员本身也是完全透明。
即ServiceMesh架构本身的技术复杂性对微服务开发人员透明。这个也正是我们在进行微服务治理管控时候最希望达到的一个效果。
在ServiceMesh架构下实现了控制流和数据流的分离,但是控制平面仍然可以拦截到数据流,并推送到类似消息中间件中。
需要的订阅端可以对消息进行订阅拿到消息报文信息,然后再对消息报文进行进行后续的日志分析。同时通过消息报文,接口服务运行实例数据的统计分析,结合我们预先配置的规则形成最终的控制规则。而Sidecar仅仅是执行最终的控制指令进行控制即可。
正是因为这样,我们可以看到,ServiceMesh架构下我们很容易集成各种日志分析工具,服务链监控工具等。同时这种集成本身又是一种松耦合的集成方式。
比如流量控制的实现,与传统的微服务架构一样,首先就需要知道在一个网格中有多少 Endpoints(端点),这些 Endpoints 都属于哪些 Service ,然后将这些信息都记录到注册中心去便于实现服务发现。Istio 也有一个 Service Registry 用来存储网格内所有可以被路由的服务列表,如果您是 Kubernetes 用户,Istio 会自动从 Kubernetes 的 Etcd 中拉取可用 Service 列表并维护到自己的 Service Registry 中。
再比如类似监控,日志,服务链跟踪等各观察性功能的实现,则更加基于已经和Kurbernetes实现集成的各种开源组件来完成即可。比如常见的,Prometheus ,ELK,Zipkin等。
是否还需要服务注册中心和API网关?
我在前面已经表达了观点,即通过Istio实现微服务治理后,不再需要类似Eureka, Consul,Nacos等服务注册中心。这些注册中心有的服务注册发现,负载均衡等能力在Istio中已经具备。
其次也不再需要类似Kong API网关进行集成。如果整个微服务架构下有API接口需要进一步对外暴露,直接通过Ngnix来实现一层DMZ区的服务代理就可以了。
对于类似SpringCloiud,Dubbo等微服务框架来说,实际上仅仅保留单个微服务模块和API接口开发发布的能力即可,而不需要再采用完整的SpringCloiud全家桶进行服务治理。
欢迎关注@人月聊IT 分享SOA,微服务,DevOps平台规划和建设。