查看原文
其他

Istio流量管理实现机制深度解析

几米宋 2022-09-06

The following article is from 赵化冰 Author 赵化冰

原创:赵化冰

由于本章节涉及到较多源代码及配置文件,在微信中阅读容易引起不适,建议点击 “查看原文”或者从电脑上打开链接: https://zhaohuabing.com/post/2018-09-25-istio-traffic-management-impl-intro/ 进行阅读。

目录


  • 前言

  • Pilot高层架构

    • 统一的服务模型

    • 标准数据面 API

    • 业务DSL语言

  • Istio流量管理相关组件

    • 控制面组件

    • 数据面组件

    • 命令行工具

  • 数据面标准API

    • 基本概念和术语

    • XDS服务接口

    • XDS服务接口的最终一致性考虑

    • ADS聚合发现服务

  • Bookinfo 示例程序分析

    • Bookinfo程序结构

    • xDS接口调试方法

    • Envoy启动过程分析

    • Envoy配置分析

    • Bookinfo端到端调用分析

  • 小结

  • 参考资料

前言

Istio作为一个service mesh开源项目,其中最重要的功能就是对网格中微服务之间的流量进行管理,包括服务发现,请求路由和服务间的可靠通信。Istio实现了service mesh的控制面,并整合Envoy开源项目作为数据面的sidecar,一起对流量进行控制。

Istio体系中流量管理配置下发以及流量规则如何在数据面生效的机制相对比较复杂,通过官方文档容易管中窥豹,难以了解其实现原理。本文尝试结合系统架构、配置文件和代码对Istio流量管理的架构和实现机制进行分析,以达到从整体上理解Pilot和Envoy的流量管理机制的目的。


Pilot高层架构



Istio控制面中负责流量管理的组件为Pilot,Pilot的高层架构如下图所示:

Pilot Architecture(来自Isio官网文档[1])

根据上图,Pilot主要实现了下述功能:

统一的服务模型

Pilot定义了网格中服务的标准模型,这个标准模型独立于各种底层平台。由于有了该标准模型,各个不同的平台可以通过适配器和Pilot对接,将自己特有的服务数据格式转换为标准格式,填充到Pilot的标准模型中。

例如Pilot中的Kubernetes适配器通过Kubernetes API服务器得到kubernetes中service和pod的相关信息,然后翻译为标准模型提供给Pilot使用。通过适配器模式,Pilot还可以从Mesos, Cloud Foundry, Consul等平台中获取服务信息,还可以开发适配器将其他提供服务发现的组件集成到Pilot中。

标准数据面API

Pilo使用了一套起源于Envoy项目的标准数据面API[2]来将服务信息和流量规则下发到数据面的sidecar中。

通过采用该标准API,Istio将控制面和数据面进行了解耦,为多种数据面sidecar实现提供了可能性。事实上基于该标准API已经实现了多种Sidecar代理和Istio的集成,除Istio目前集成的Envoy外,还可以和Linkerd, Nginmesh等第三方通信代理进行集成,也可以基于该API自己编写Sidecar实现。

控制面和数据面解耦是Istio后来居上,风头超过Service mesh鼻祖Linkerd的一招妙棋。Istio站在了控制面的高度上,而Linkerd则成为了可选的一种sidecar实现,可谓降维打击的一个典型成功案例!

数据面标准API也有利于生态圈的建立,开源,商业的各种sidecar以后可能百花齐放,用户也可以根据自己的业务场景选择不同的sidecar和控制面集成,如高吞吐量的,低延迟的,高安全性的等等。有实力的大厂商可以根据该API定制自己的sidecar,例如蚂蚁金服开源的Golang版本的Sidecar MOSN(Modular Observable Smart Netstub)(SOFAMesh中Golang版本的Sidecar);小厂商则可以考虑采用成熟的开源项目或者提供服务的商业sidecar实现。

备注:Istio和Envoy项目联合制定了Envoy V2 API,并采用该API作为Istio控制面和数据面流量管理的标准接口。

业务DSL语言

Pilot还定义了一套DSL(Domain Specific Language)语言,DSL语言提供了面向业务的高层抽象,可以被运维人员理解和使用。运维人员使用该DSL定义流量规则并下发到Pilot,这些规则被Pilot翻译成数据面的配置,再通过标准API分发到Envoy实例,可以在运行期对微服务的流量进行控制和调整。

Pilot的规则DSL是采用K8S API Server中的Custom Resource (CRD)[3]实现的,因此和其他资源类型如Service Pod Deployment的创建和使用方法类似,都可以用Kubectl进行创建。

通过运用不同的流量规则,可以对网格中微服务进行精细化的流量控制,如按版本分流,断路器,故障注入,灰度发布等。

Istio流量管理相关组件



我们可以通过下图了解Istio流量管理涉及到的相关组件。虽然该图来自Istio Github old pilot repo, 但图中描述的组件及流程和目前Pilot的最新代码的架构基本是一致的。


Pilot Design Overview (来自Istio old_pilot_repo[4])


图例说明:图中红色的线表示控制流,黑色的线表示数据流。蓝色部分为和Pilot相关的组件。

从上图可以看到,Istio中和流量管理相关的有以下组件:

控制面组件

Discovery Services

对应的docker为gcr.io/istio-release/pilot,进程为pilot-discovery,该组件的功能包括:

  • 从Service provider(如kubernetes或者consul)中获取服务信息

  • 从K8S API Server中获取流量规则(K8S CRD Resource)

  • 将服务信息和流量规则转化为数据面可以理解的格式,通过标准的数据面API下发到网格中的各个sidecar中。

K8S API Server

提供Pilot相关的CRD Resource的增、删、改、查。和Pilot相关的CRD有以下几种:

  • Virtualservice:用于定义路由规则,如根据来源或 Header 制定规则,或在不同服务版本之间分拆流量。

  • DestinationRule:定义目的服务的配置策略以及可路由子集。策略包括断路器、负载均衡以及 TLS 等。

  • ServiceEntry:用 ServiceEntry 可以向Istio中加入附加的服务条目,以使网格内可以向istio 服务网格之外的服务发出请求。

  • Gateway:为网格配置网关,以允许一个服务可以被网格外部访问。

  • EnvoyFilter:可以为Envoy配置过滤器。由于Envoy已经支持Lua过滤器,因此可以通过EnvoyFilter启用Lua过滤器,动态改变Envoy的过滤链行为。我之前一直在考虑如何才能动态扩展Envoy的能力,EnvoyFilter提供了很灵活的扩展性。


数据面组件

在数据面有两个进程Pilot-agent和envoy,这两个进程被放在一个docker容器gcr.io/istio-release/proxyv2中。

Pilot-agent

该进程根据K8S API Server中的配置信息生成Envoy的配置文件,并负责启动Envoy进程。注意Envoy的大部分配置信息都是通过xDS接口从Pilot中动态获取的,因此Agent生成的只是用于初始化Envoy的少量静态配置。在后面的章节中,本文将对Agent生成的Envoy配置文件进行进一步分析。

Envoy

Envoy由Pilot-agent进程启动,启动后,Envoy读取Pilot-agent为它生成的配置文件,然后根据该文件的配置获取到Pilot的地址,通过数据面标准API的xDS接口从pilot拉取动态配置信息,包括路由(route),监听器(listener),服务集群(cluster)和服务端点(endpoint)。Envoy初始化完成后,就根据这些配置信息对微服务间的通信进行寻址和路由。

命令行工具

kubectl和Istioctl,由于Istio的配置是基于K8S的CRD,因此可以直接采用kubectl对这些资源进行操作。Istioctl则针对Istio对CRD的操作进行了一些封装。Istioctl支持的功能参见该表格。

数据面标准API



前面讲到,Pilot采用了一套标准的API来向数据面Sidecar提供服务发现,负载均衡池和路由表等流量管理的配置信息。该标准API的文档参见Envoy v2 API[5]。Data Plane API Protocol Buffer Definition[6])给出了v2 grpc接口相关的数据结构和接口定义。

(备注:Istio早期采用了Envoy v1 API,目前的版本中则使用V2 API,V1已被废弃)。

基本概念和术语

首先我们需要了解数据面API中涉及到的一些基本概念:

  • Host:能够进行网络通信的实体(如移动设备、服务器上的应用程序)。在此文档中,主机是逻辑网络应用程序。一块物理硬件上可能运行有多个主机,只要它们是可以独立寻址的。在EDS接口中,也使用“Endpoint”来表示一个应用实例,对应一个IP+Port的组合。

  • Downstream:下游主机连接到 Envoy,发送请求并接收响应。

  • Upstream:上游主机接收来自 Envoy 的连接和请求,并返回响应。

  • Listener:监听器是命名网地址(例如,端口、unix domain socket等),可以被下游客户端连接。Envoy 暴露一个或者多个监听器给下游主机连接。在Envoy中,Listener可以绑定到端口上直接对外服务,也可以不绑定到端口上,而是接收其他listener转发的请求。

  • Cluster:集群是指 Envoy 连接到的逻辑上相同的一组上游主机。Envoy 通过服务发现来发现集群的成员。可以选择通过主动健康检查来确定集群成员的健康状态。Envoy 通过负载均衡策略决定将请求路由到哪个集群成员。

XDS服务接口

Istio数据面API定义了xDS服务接口,Pilot通过该接口向数据面sidecar下发动态配置信息,以对Mesh中的数据流量进行控制。xDS中的DS表示discovery service,即发现服务,表示xDS接口使用动态发现的方式提供数据面所需的配置数据。而x则是一个代词,表示有多种discover service。这些发现服务及对应的数据结构如下:

  • LDS (Listener Discovery Service) envoy.api.v2.Listener

  • CDS (Cluster Discovery Service) envoy.api.v2.RouteConfiguration

  • EDS (Endpoint Discovery Service) envoy.api.v2.Cluster

  • RDS (Route Discovery Service) envoy.api.v2.ClusterLoadAssignment

XDS服务接口的一致性考虑

xDS的几个接口是相互独立的,接口下发的配置数据是最终一致的。但在配置更新过程中,可能暂时出现各个接口的数据不匹配的情况,从而导致部分流量在更新过程中丢失。

设想这种场景:在CDS/EDS只知道cluster X的情况下,RDS的一条路由配置将指向Cluster X的流量调整到了Cluster Y。在CDS/EDS向Mesh中Envoy提供Cluster Y的更新前,这部分导向Cluster Y的流量将会因为Envoy不知道Cluster Y的信息而被丢弃。

对于某些应用来说,短暂的部分流量丢失是可以接受的,例如客户端重试可以解决该问题,并不影响业务逻辑。对于另一些场景来说,这种情况可能无法容忍。可以通过调整xDS接口的更新逻辑来避免该问题,对上面的情况,可以先通过CDS/EDS更新Y Cluster,然后再通过RDS将X的流量路由到Y。

一般来说,为了避免Envoy配置数据更新过程中出现流量丢失的情况,xDS接口应采用下面的顺序:

  1. CDS 首先更新Cluster数据(如果有变化)

  2. EDS 更新相应Cluster的Endpoint信息(如果有变化)

  3. LDS 更新CDS/EDS相应的Listener。

  4. RDS 最后更新新增Listener相关的Route配置。

  5. 删除不再使用的CDS cluster和 EDS endpoints。

ADS聚合发现服务

保证控制面下发数据一致性,避免流量在配置更新过程中丢失的另一个方式是使用ADS(Aggregated Discovery Services),即聚合的发现服务。ADS通过一个gRPC流来发布所有的配置更新,以保证各个xDS接口的调用顺序,避免由于xDS接口更新顺序导致的配置数据不一致问题。

关于XDS接口的详细介绍可参考xDS REST and gRPC protocol[7]

Bookinfo示例程序分析



下面我们以Bookinfo为例对Istio中的流量管理实现机制,以及控制面和数据面的交互进行进一步分析。

本章节会介绍Istio控制面如何将服务和路由信息通过xDS接口下发到数据面中;解释Envoy上生成的各种配置数据的结构,包括listener,cluster,route和endpoint。

然后分析一个端到端的调用请求,通过调用请求的流程把这些配置串连起来,以从全局上理解Istio控制面的流量控制是如何在数据面的Envoy上实现的。

下图描述了一个Productpage服务调用Details服务的请求流程:

由于本章节涉及到较多源代码及配置文件,在微信中展示效果较差,请点击 “查看原文”或者从电脑上打开链接: https://zhaohuabing.com/post/2018-09-25-istio-traffic-management-impl-intro/

相关阅读

  • SOFAMesh - https://github.com/alipay/sofa-mesh 基于Istio的大规模服务网格解决方案

  • SOFAMosn - https://github.com/alipay/sofa-mosn 使用Go语言开发的高性能Sidecar代理

合作社区

参与社区

以下是参与ServiceMesher社区的方式,最简单的方式是联系我!

  • 加入微信交流群:关注本微信公众号后访问主页右下角有获取联系方式按钮,添加好友时请注明姓名-公司

  • 社区网址:http://www.servicemesher.com

  • Slack:https://servicemesher.slack.com (需要邀请才能加入)

  • GitHub:https://github.com/servicemesher

  • Istio中文文档进度追踪:https://github.com/servicemesher/istio-official-translation

  • Twitter: https://twitter.com/servicemesher

  • 提供文章线索与投稿:https://github.com/servicemesher/trans


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存