2020-06-11【Istio组件Mixer的前世今生】

美国波浪谷,有生之年还能打卡吗?

今日鸡汤

对每个人而言,真正的职责只有一个:找到自我,然后在心中坚守一生,全心全意,永不停息。所有其他的路都是不完整的,是人的逃避方式,是对大众理想的懦弱回归,是随波逐流,是对内心的恐惧。

愿你能够幸运的找到自我,并坚守一生。

上次说到:

Prometheus采用Pull方式搜集被监控对象的Metrics,将这些数据保存在时序数据库中,之后可以按照时间进行检索。

Istio如何收集指标——Mixer 到 Mixerless

先看看1.5版本前的方式

在1.5版本前,Istio还采用的是各个控制组件各司其职的方式,Istio使用Mixer做为独立的遥测后端,数据采集不需要Envoy来做,真正实现应用、代理、遥测后端三方解耦的功能。

Mixer的设计哲学——搞中介

Mixer作为Istio与开放基础设施之间的抽象层,提供了一种中介模式,允许通过配置不同的Adapter连接不同的后端,从而使运行在Service Mesh中的服务可以不直接访问后端接口就直接与后端交互。同时,通过使用不同的插件,使Mixer能暴露一致的API,在运行时通过配置就能切到不同后端,非常灵活。

引用官方文档对Mixer的定义:

Mixer 本质上就是一个处理属性和路由的机器。代理将属性作为预检和遥测报告的一部分发送出来,并且转换为一系列对适配器的调用。运维人员提供了用于描述如何将传入的属性映射为适配器的配置。


Mixer的设计

简单说来,它的目标就是减少业务系统的复杂性,将策略逻辑从业务的微服务的代码转移到Mixer中, 并且改为让运维人员控制。

Mixer有什么功能?

Mixer可不仅仅是为了遥测而生,其实它还负责预检和配额,这两个功能的加持也是后面它被吐槽的很凶原因。

总结来说,Mixer 提供三个核心功能:

  • 前提条件检查。允许服务在响应来自服务消费者的传入请求之前验证一些前提条件。前提条件包括认证,黑白名单,ACL检查等等。
  • 配额管理。使服务能够在多个维度上分配和释放配额。典型例子如限速。
  • 遥测报告。使服务能够上报日志和监控。

在Istio内,由于Envoy只是个干活的小兵,因此它也重度依赖Mixer。

监控的都是什么数据?

监控的是一种称为”属性“的一小部分数据,来描述请求信息和请求的环境,比如请求大小、响应情况、源IP地址等。各个Envoy会给Mixer吐数进行上报。

数据怎么传递的?

整个过程权责明确,以Prometheus作为后端为例,主要有四个步骤:
1)Envoy批量将请求属性(描述请求或服务运行环境的一些元信息)通过Report接口异步上报给Mixer;
2)Mixer根据handler配置将Instance转换为Prometheus Adapter需要的格式;
3)Prometheus Adapter通过HTTP接口发布Metric数据;
4)Prometheus拉取、存储Metric数据,并提供Query接口进行检索。

Prometheus 默认监控指标?

Mixer 安装中默认包含一个 Prometheus Adapter,Adapter会收到一份用于生成默认监控指标的配置,比如,对HTTP来说,包括Request Count、Request Duration、Request Size、Response Size。 所以当安装好Istio,Prometheus实例可以直接抓取 Mixer 以获取默认指标。

Istio附带了一组默认的dashboard,根据指标来监控服务,比如istio_requests_total

istio_requests_total

如何配置Adapter自定义监控指标?

Adapter的配置主要有三个重要对象:

  • Instance:Instance描述如何将请求属性到Adapter输入的映射。
# Configuration for metric instances
apiVersion: config.istio.io/v1alpha2
kind: instance
metadata:
  name: doublerequestcount
  namespace: istio-system
spec:
  compiledTemplate: metric
  params:
    value: "2" # count each request twice
    dimensions:
      reporter: conditional((context.reporter.kind | "inbound") == "outbound", "client", "server")
      source: source.workload.name | "unknown"
      destination: destination.workload.name | "unknown"
      message: '"twice the fun!"'
    monitored_resource_type: '"UNSPECIFIED"'
  • Handler:描述Adapter和它的配置,在这里配置的就是prometheus的Adapter,这里就定义了一个叫做double_request_count的prometheus监控指标。
# Configuration for a Prometheus handler
apiVersion: config.istio.io/v1alpha2
kind: handler
metadata:
  name: doublehandler
  namespace: istio-system
spec:
  # convert collected instances to Prometheus format
  compiledAdapter: prometheus
  params:
    metrics:
    - name: double_request_count # Prometheus metric name
      instance_name: doublerequestcount.instance.istio-system # Mixer instance name (fully-qualified)
      kind: COUNTER
      label_names:
      - reporter
      - source
      - destination
      - message
  • Rule:定义了哪个Instance在什么时候被发送到哪个Handler来处理,一般包含一个表达式和一个Action。匹配表达式控制何时调用Adapter,Action决定Adapter的Instance集。
# Rule to send metric instances to a Prometheus handler
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
  name: doubleprom
  namespace: istio-system
spec:
  actions:
  - handler: doublehandler
    instances: [ doublerequestcount ]

Istio1.5后

在Istio1.5版本后,Istio抛弃了饱受诟病的Mixer,转为使用Telemetry V2进行遥测数据收集。那Mixer为什么被吐槽呢?从它的设计说起。

性能永远是软件的试金石

之前采用的是Mixer与Proxy分离的架构,这种架构为什么不好?
先说优美之处,有三点:

  1. 分离的设计意味着Mixer的变动不影响sidecar;
  2. Sidercar不需要跟Adapter耦合;
  3. 如果需要替换数据平面的需求,可以直接换掉。

缺陷也很明确,性能差。

istio1.1前的架构
Istio1.1后的架构

可以看到,区别就在于,Mixer将进程内Adapter优化为进程外Adapter,也就是说,把Adapter的进程从Mixer里移出来了,改为独立于Mixer的单独进程。虽然这一波操作将Out-of-process Adapter从Istio移出来了,让Istio的设计变得更简单,但是却收获了更多的吐槽,原因有两个:其一,多一个组件反而增加运维人员的工作。其二,这种设计并没有减少Sidecar与Mixer之间远程调用的次数,反而在Mixer和Out-of-process Adapter之间增加了一次远程调用。



你说这个设计是不是蜜汁尴尬!!本来是为了解决性能问题,结果还导致甩锅和更大的性能问题,可能架构师只追求架构图的完美而忽略了实际生产的根本需求。

这是对Mixer遥测功能性能的“优化”,你还记得吗?Mixer还负责预检呢。预检就是在转发请求前,把请求拦下来,做前提条件检查和配额管理,只有满足条件的请求才会被转发。为了做这个事情,Envoy还需要跟Mixer发一次请求,并且这个请求不能做成异步哦,因为它是前提条件检查哦。

也就是说,为了帮助Mixer完成它的工作,Envoy在转发请求前要发起一次对Mixer的请求做预检和配额管理,在转发请求后还要再发一次请求做上报。后一次可以是异步,但前一次只能是同步。

于是,为了解决这个问题,神奇的架构师灵机一动,想到了性能问题的大招——缓存。
于是乎,在Envoy中增加Mixer Filter负责和Mixer来通讯,它里面保存有策略判断所需的数据缓存,因此大部分策略判断在Envoy中就处理了,不需要发送请求到Mixer。另外Envoy收集到的遥测数据会先保存在Envoy的缓存中,每隔一段时间再通过批量的方式上报到Mixer。

虽然增加了缓存机制,但是性能依旧很烂。


另外,当所有的流量通过Mixer来统一采集和上报,导致规模上来后,Mixer容易成为性能瓶颈。这也是被吐槽的很惨的一个重要原因。

解法——Web Assembly

天下合久必分,分久必合,既然分开不好,那么很自然的就想要把Mixer的功能合并到Sidecar做,将遥测和服务鉴权能力下沉到每个服务的代理Proxy Envoy中。
这机智的大脑,那问题来了,Envoy是C++写的,Mixer是Go的,怎么把功能加进去?直接撸袖子再写一把C++吗?
纠结了很久,Envoy开始提供Web Assembly(WASM)的支持,成了扩展Envoy解药。那什么是Web Assembly,我的理解也不是很深刻,摘抄一下:

WebAssembly不是一门编程语言,而是一份字节码标准。WebAssembly字节码是一种抹平了不同CPU架构的机器码,WebAssembly字节码不能直接在任何一种CPU架构上运行,但由于非常接近机器码,可以非常快的被翻译为对应架构的机器码,因此WebAssembly运行速度和机器码接近。(类比Java bytecode)

Envoy支持了WASM后,无论用哪种高级语言写的各路Adapter,都可以编译成WASM,然后被Envoy加载,这样就避免了修改Envoy,也不再需要远程调用了。
也是被逼到没办法了,开了如此拍案叫绝的脑洞呀。


Mixerless的实现——Telemetry V2

正如官博《重新定义代理的扩展性:Envoy 和 Istio 引入 WebAssembly》所说:

WebAssembly是一种针对代理服务扩展的新接口,可以把 Istio 的扩展从控制平面迁移到 sidecar 代理中。

目前在Envoy中,有4个内置的WebAssembly扩展:

  • access_log_policy和stackdriver:用于往Google StackDriver推送数据
  • metadata_exchange:做request和response上下游标记,记录请求
  • stats:采集请求相关监控指标,暴露Prometheus 可采集的接口。

目前istio默认生成的标准指标可以通过这里查到:Istio标准度量指标,我专门从官方文档比了一下,默认的指标没有变化:

Mixer和Telemetry v2默认指标比较

标签也基本一样,只不过Telemetry v2增加了一个叫做“规范服务”的标签:


Telemetry v2新增标签.png

纠结了很久的如何定制Metrics也终于找到了官方的wiki来说明:Configurable Metrics without Mixer。大致分两步:

  • 第一步,配置EnvoyFilter。
  • 第二步,在pod中添加annotations。不难理解,由于遥测下沉到Envoy了,因此每一个pod都需要将想要让Prometheus监控的指标声明出来。
    具体怎么操作,接下来会翻译加实操一下,敬请期待。

另外,如果你想写自己的扩展,可以使用Solo.io发布的工具WebAssembly Hub,官方介绍为:

这是一套为 Envoy 和 Istio 做的,用于构建,部署,共享和发现 Envoy Proxy Wasm 扩展的工具和仓库。用户可以轻松地把任何受支持语言开发的代码编译为 Wasm 扩展。可以将这些扩展上传到 Hub 仓库,并且用单个命令就将其在 Istio 中部署和删除。

本宝宝准备过两天也照着文档试一下WebAssembly Hub,看看怎么使,到时候再跟大家分享啦。

你可能感兴趣的:(2020-06-11【Istio组件Mixer的前世今生】)