本文为Istio系列的终结篇,前两篇《Istio系列一:Istio的认证授权机制分析》、《Istio系列二:Envoy组件分析》笔者分别对Istio的安全机制和数据平面组件Envoy进行了解读,相信各位读者已经对Istio有了一定认识,本文主要对Istio的控制平面核心组件Mixer、Pilot进行分析解读,在文中笔者会结合Envoy说明Mixer、Pilot的工作原理及它们在Istio中的价值,文章阅读时间大致15分钟,希望能给各位读者带来收获。
一、Pilot组件分析
Istio 流量管理的核心组件是 Pilot,它管理和配置部署在特定Istio服务网格中的所有Envoy代理实例。Pilot还允许用户指定在 Envoy 代理之间使用什么样的路由流量规则,并配置故障恢复功能,如超时、重试和熔断器。它还维护了网格中所有服务的规范模型,并使用这个模型通过DS(发现服务)让 Envoy 了解网格中的其它实例。
图1为官方Pilot架构图,图2为笔者画的Pilot拓扑图,如下所示:
图1 Pilot架构图
图2 Pilot拓扑图
Pilot可以将应用程序流量管理从其依赖环境中解耦出来,给用户提供了便利性,而用户怎样通过Pilot去对流量进行管理呢?首先简单介绍下Pilot组件中含有的模块:
1
Abstract Model、Platform Adapater
首先Pilot定义了网格服务中的标准模型,即图1中的Abstract Model,服务标准模型独立于各种底层平台,例如Kubernetes、Mesos、Cloud Foundry等。各个平台可以通过Platform Adapter和Pilot进行对接,将自己持有的元数据(以Kubernetes举例,元数据为Pod,Service,Endpoints等)转化为Abstract Model标准格式,并填充到标准模型中。另外Platform Adapter是可插拔的,开发人员也可以自己开发Platform Adapter去适配其它服务发现组件集成至Pilot中。这里注意Istio的服务发现用的是各个底层平台原有的功能,比如Kubernetes平台使用kube-dns或core-dns做服务发现。Pilot通过在Kubernetes里注册一个Controller来监听事件,从而获取Service和Kubernetes的Endpoint以及Pod等元数据。
2
Envoy API
Pilot还提供了一套EnvoyAPI(标准数据面API)来将服务信息和流量暴露至数据平面的Envoy中。
所以Istio通过标准API的设计,将控制平面与数据平面解耦,除了Istio集成Envoy,Istio还可以集成Linkerd、Nginmesh等其它代理软件,当然也可以基于该API自己编写Sidecar实现。目前Istio和Envoy制定了Envoy V2 API,V1已废弃。
3
Discovery Service
基于以上对Pilot四个模块的描述结合图1,2,Pilot的基本工作流程可描述如下:
二、Mixers组件分析
在传统的软件架构中应用代码与后端基础设施(例如访问控制系统,日志系统,监控系统,ACL检查,配额执行系统等)间的耦合度较高,这样无疑给业务维护带来了复杂性。在Istio架构中,Mixer充当应用代码和后端基础设施的中间层,在应用代码侧将复杂策略转换为运维人员易懂的yaml文件并通过下发方式实现;在后端基础设施侧,通过后端基础设施的API与Mixer做集成,从而将应用代码与后端基础设施间的耦合度彻底解开,这种设计方式也同时遵循Istio设计之初的理念。
Mixer的核心功能有两个,分别是:
图3为Mixer的官方架构图,图4为笔者画的Mixer拓扑图,如下所示:
图3 Mixer架构图
图4 Mixer拓扑图
Mixer组件主要功能为check(前置条件检查)和report(上报遥测数据), 这两个功能在Mixer中以RPC(Remote Procedure Call)的形式对外呈现,为了更清晰的理解上述拓扑图中的Mixer工作流程,首先介绍Mixer组件的几个重要概念:
Attributes
Attributes由Envoy提供,主要是用来描述所有出入Envoy代理流量产生的环境, Envoy将这些环境(Attributes)传递给后端各个Adapter供使用,Attributes主要包括API请求状态码、请求响应时间、网络地址、请求路径、请求参数等。关于Attributes的所有词汇可以查看官方文档,属性类型也可查看官方文档,下面是一组简单的Attributes:
request.path:xyz/abc
request.size:234
request.time:11:07:35.234 02/19/2019
source.ip:192.168.0.1
destination.service:example
Reference Attributes
即引用属性,在Mixer工作流中,由于Envoy不知道基础设施后端会引用哪些属性从而会先将所有的属性一并发给Mixer的基础设施后端做前置条件检查(check rpc),检查过程中会根据基础设施实际使用到的属性进行筛选,将实际会用到的属性作为引用属性返回给Envoy,下图展示check rpc的大致过程:
图5 mixer 前置条件检查过程图
由上图可知Mixer调度的多个Adapters只用到了request、path、request。size、request、time这三个属性,那么这三个属性将被作为引用属性返回给Envoy。Envoy进行代理转发后再根据check rpc返回的[lw1] [PM2] [lw3] 引用属性向Mixers的report rpc发起调用。或许会有读者疑问为何Istio在设计Mixer时会用到引用属性这一概念?并且需要将此属性返回给Envoy?答案其实也很简单,从图4可看出在Envoy和Mixer组件中包含两级缓存,check rpc返回的引用属性被缓存至Envoy侧所在的一级缓存中,从而避免了多次重复请求给Mixer带来的性能开销,同时Mixer也将各个Adapter使用的具体属性缓存至Mixer侧所在的二级缓存中。
Adapter
适配器,Mixer是个可扩展组件,内部提供多个Adapter。Mixer 通过使用通用插件模型实现不同基础设施后端的灵活性。每个插件都被称为 Adapter,Mixer通过它们与不同的基础设施后端连接,这些后端可提供核心功能,例如日志、监控、配额、ACL 检查等。通过配置能够决定在运行时使用确切的适配器套件,并且可以轻松扩展到新的或定制的基础设施后端。默认基础设施后端具体如下图所示:
图6 Mixer Adpater
结合以上Mixer基本概念和图4拓扑图,Mixer的工作流程可描述如下:
从Mixer的工作流程可看出其存在一些问题,每有请求进来,Envoy便会调用两次请求给Mixer,在微服务规模较小时,似乎不会有太大影响,但生产环境中微服务数量到达成千上百时无疑会对网络资源,内存资源消耗巨大,那么有什么好的解决方式吗?
在Istio早期版本中,由于没有将生产环境所需因素考虑其中,所以性能问题一直成为诟病,随着Istio版本迭代更新,目前默认的解决方案是在每个Envoy端和Mixer端放置一级缓存和二级缓存。从而可以有效减少Envoy对Mixer后端的调用频率,在一定程度上降低了网络开销。从图4的Mixer拓扑图可看出绿色框部分即为Mixer缓存模块。
Mixer中实现 “前置条件检查”和“上报遥测数据”两个RPC请求需要用户自定义yaml文件并通过Envoy下发实现。Promethues作为Mixer默认的后端基础设施,用于对Istio中运行的微服务进行监控。下面以Promethues作为用户“前置条件检查”和“上报遥测数据”的后端基础设施,将用户下发的yaml文件拆分为Handler、Instance(Template)、Rule三部分进行说明:
1
Instance(Template)
Instance对应Promethues需要的一组属性数据, 下图spec。dimensions字段值(即source_version、destination_service、destination_version、response_code)代表一组属性表达式,在Promethues进行监控时会被用到。Mixer Instance(Template)如下所示:
apiVersion:"config.istio.io/v1alpha2"
kind:metric
metadata:
name:requestsize
namespace:istio-system
spec:
value:request.size | 0
dimensions:
source_version:source.labels["version"] | "unknown"
destination_service:destination.Service.host | "unknown"
destination_version:destination.labels["version"] | "unknown"
response_code:response.code | 200
monitored_resource_type:'"UNSPECIFIED"'
2
Handler
Handler用于对Promethues进行配置,并对请求的属性进行捕获,可以理解为配置好的Promethues实例,由下图spec.metrics.name字段值可看出Promethues的度量标准为request_count,即对服务的请求数量进行统计监测。其中spec.metrics.label_names为Promethues所需的属性值,不难看出label_names(destination_service、destination_version、response_code)对应着Instance中的spec.dimensions字段值。那么Instance何时调用Handler实例并最终进行监控操作呢?yaml文件的第三部分Rule就是用来做这个的。Mixer Handler如下所示:
apiVersion:config.istio.io/v1alpha2
kind:prometheus
metadata:
name:handler
namespace:istio-system
spec:
metrics:
- name:request_count
instance_name:requestcount.metric.istio-system
kind:COUNTER
label_names:
- destination_service
- destination_version
- response_code
3
Rule
Rule用于定义某特定Instance调用Handler的时机,比如我们要把目标服务为service1,并且请求头中带有 x-user 的 requestduration 指标发送给 Prometheus Handler。如下所示:
apiVersion:config.istio.io/v1alpha2
kind:rule
metadata:
name:promhttp
namespace:istio-system
spec:
match:destination。service == "service1.ns.svc.cluster.local" && request。headers["x-user"] == "user1"
actions:
- handler:handler.prometheus
instances:
- requestduration.metric.istio-system
spec.match用于前置检查,如果检查通过会执行spec.actions中的内容,actions包含了一个实例requestduration.metric.istio-system,这个实例会分发给Handler。
三、总结
Istio作为一款开源微服务管理软件,因其优秀的设计受到了许多大厂的青睐,但Mixer组件的性能问题似乎都被大厂认为是最大诟病因此在生产环境中不得不舍弃或被替换掉,Istio也将Mixer设立了禁止和启用,开发者可以按需所取。作为流量管理的Pilot组件,以Envoy API的方式与数据平面组件Envoy进行交互不仅提升了效率,并且降低了整个系统组件间耦合度;其内部Platform Adapter模块可以与各大编排工具适配,目前在Kubernetes上已达到无缝适配,但对Mesos、CloudFoundry的完美支持还有待时间的考验。
Service Mesh的出现加快了微服务的发展,大多数开发或是运维人员逐步由Spring Cloud框架转向Istio的学习,Istio的影响力自然不必多说,那么下一个使用者会是你吗?
内容编辑:星云实验室 浦明 责任编辑:肖晴