ServiceMesh-istio(二)

ServiceMesh-istio(二)

那么我们今天来看下 Istio 的可观测性的实现。首先要说的就是 Mixer 组件,它是一个独立于平台的组件,负责在 Istio 中执行访问控制和使用策略,并从 Envoy Sidecar 和其他服务收集遥测数据。

Mixer提供三个核心功能:

  1. Precondition Checking: 前置条件检查。在服务响应外部请求前,通过Envoy Sidecar 向 Mixer 发送 Check 请求,检查该请求是否满足一定的前提条件,包括黑白名单检查、ACL 检查等。
  2. Quota Management: 配额管理。配额被用作相对简单的资源管理工具,使服务能够在多个维度上分配和释放配额,避免多个请求争抢资源。
  3. Telemetry Reporting: 遥测报告。当服务处理完请求后,通过 Envoy Sidecar 向 Mixer 上报响应时间、日志、度量等信息,生成日志记录,监控,跟踪和计费流。

Mixer 还是高度模块化和可扩展的组件,他的一个关键功能就是通过适配器模型把不同后端的策略和遥测收集系统的细节抽象出来,使得 Istio 可以与一组开放式基础设施后端进行交互。
注:基础设施后端旨在提供用于构建服务的支持功能。它们包括访问控制系统,遥测捕获系统,配额执行系统,计费系统等等。

从上图中我们还可以看出,网格中每个服务实例旁的 Sidecar 具有本地缓存,从而可以在缓存中执行相对较大比例的前提条件检查,减少 Mixer 的调用频率。Mixer 可用作 Sidecar 的高度扩展且高度可用的二级缓存,有助于减少对后端的调用频率,并且有时可以减少发送到后端的数据量(通过本地聚合),而且即使在后端无响应时也能继续运行,从而有助于屏蔽基础设施后端故障。

Mixer 工作流程概括

Mixer 本质上是一个属性处理机。网格中每个服务实例旁的 Envoy Sidecar 向 Mixer 发送 Check 请求并提供 request 级别的属性数据发送给 Mixer,Mixer 再根据配置模型把属性集转化为结构型值,并把这些值调度到一组适配器上,做前置条件检查和配置管理,检查通过后才能响应。当服务处理完请求后,通过 Envoy Sidecar 向 Mixer 发送 Report 请求上报遥测数据,最后适配器把遥测数据发送给基础设施后端实现日志记录、监控指标采集展示、配额管理、ACL检查等功能。

所以除了上面我们说的基础设施后端,这里又出现了3个新名词,属性、适配器和配置模型。

Attribute 属性

属性是有名称和类型的元数据,用于描述特定服务请求或请求环境的属性的一小段数据,比如:请求响应代码码、响应时间、请求来自哪里等。Istio 中的主要属性是由 Envoy 生成,但专用的 Mixer 适配器也可以生成属性。Istio 用属性来控制服务在 Service Mesh 中运行时行为。

通用基准属性集属性表达式

Adapter 适配器

上面我们提到 Mixer 使用通用插件模型实现基础设施后端的灵活性和可扩展性,每个插件都被称为 Adapter,Mixer 通过适配器与不同的基础设施后端连接,这些后端旨在提供用于构建服务的支持功能,包括访问控制系统,遥测捕获系统,配额执行系统,计费系统等等。通过配置能够决定在运行时使用的确切的适配器套件,并且可以轻松扩展到新的或定制的基础设施后端,这样也减少了系统的复杂性。

整体架构图:

Istio内置的部分adapters举例如下:

  • circonus:一个微服务监控分析平台。
  • cloudwatch:一个针对AWS云资源监控的工具。
  • fluentd:一款开源的日志采集工具。
  • prometheus:一款开源的时序数据库,非常适合用来存储监控指标数据。
  • statsd:一款采集汇总应用指标的工具。
  • stdio:stdio适配器使Istio能将日志和metrics输出到本地,结合内置的ES、Grafana就可以查看相应的日志或指标了。

举个例子:一个类型为 listchecker 的适配器,且定义了要调用一个名为 listentry 的模板。

Template 模板

通常对于进入到 Mesh 服务中的请求,Mixer 会发生两次调用,一次是 check,一次是 report。每一次调用,Mixer 都会调用一个或多个的适配器。不同的适配器需要不同的属性作为输入来处理,例如,日志适配器需要日志输入,metric 适配器需要 metric 数据作为输入,认证的适配器需要证书等等。因此 Mixer 还提供了一组模板,每个模板定义了从特定请求的属性到适配器输入的映射关系。一个适配器可以支持任意数量的模板,一个模板也可以被传递给一个或多个适配器。

上图中类型为 listchecker 的适配器中定义要使用的模板 listentry 里面定义了一个描述符(如下图所示),看源码就会知道里面定义的是 Instance 数据结构和 Handler 的接口。

配置模型

1. Handler 处理器

Mixer 使用的每个适配器都需要一些配置才能运行。Handler 就是为适配器提供完整配置。对同一个适配器可以有任意数量的 Handler,这样就可以在不同的场景下复用了。如下图中,staticversion 的 Handler 中,定义给类型为 listchecker 的适配器提供配置,根据参数列表中定义可知当 Adapter 检查到配置不使用黑名单模式且输入值存在于列表之中(v1或v2),才返回成功。

2. Instance 实例

通过配置 Instance 将请求中的属性映射成为适配器的输入。如下图中,一个叫 lisentry 的 Instance 要从属性中获取源实例版本号得值。

3. Rule 规则

通过创建 rules 实现告诉 Mixer 哪个 instance 在什么时候发送给哪个 handler。每个规则都会指定一个特定的处理程序和要发送给该处理程序的实例。当 Mixer 处理一个调用时,它会调用指定的处理程序,并给他一组特定的处理实例。规则中包含有一个 match 元素,用于前置检查,如果检查通过则会执行动作列表。动作中包含了一个实例列表,这个列表将会分发给 Handler。
比如下图中,如果检查到目标实例的标签“app“的值为 ratings,才把 Instance: lisentry 分发给 Handler: staticversion。

Mixer 工作流程总结

还是上面这个例子。当应用实例收到请求被 envoy 拦截,envoy 根据请求生成指定的属性并向 Mixer 发送 Check 请求,Mixer 进行前置条件检查和配额检查,根据 rule 定义如果查到到目标实例的标签“app“的值为 ratings,才把 Instance: lisentry 分发给 Handler: staticversion,Handler 将 Instance 获取到的源实例版本号的值传递给 adapter: listchecker (template已经初始化好数据格式),要求 Adapter 检查到配置不使用黑名单模式且输入值存在于列表之中(v1或v2),才返回成功。接着 Envoy 分析返回结果,决定执行请求或拒绝请求。若可以执行请求则执行请求。请求完成后 envoy 再向 Mixer gRPC 服务发起 Report rpc 请求,上报遥测数据。最后适配器再把遥测数据发送给基础设施后端做进一步处理。

希望到这里能让你觉得比官网说的明白。时间还早把 tracing 也说了。

Tracing 追踪

链路追踪是一个很强大的工具,可以帮助我们对应用做性能分析和快速的故障定位,在 Linkerd2.0 中我们也见识过。

Jaeger

Istio 默认支持 Jaeger 做分布式追踪。Jaeger 是 Uber 推出的一款开源分布式追踪系统,兼容 OpenTracing API。使用 Jaeger 可以非常直观的展示整个分布式系统的调用链,由此可以很好发现和解决问题。

专业名词解析:

  • Trace:追踪对象,一个Trace代表了一个服务或者流程在系统中的执行过程,如:test.com,redis,mysql等执行过程。一个Trace由多个span组成。
  • span:记录Trace在执行过程中的信息,如:查询的sql,请求的HTTP地址,RPC调用,开始、结束、间隔时间等。
  • 无限极分类:服务与服务之间使用无限极分类的方式,通过HTTP头部或者请求地址传输到最低层,从而把整个调用链串起来。

架构图及组件介绍:

  • Jaeger-Agent 是一个网络守护进程,监听通过 UDP 发送过来的 Span,它会将其批量发送给 collector。按照设计,Agent 要被部署到所有主机上,作为基础设施。Agent 将 collector 和客户端之间的路由与发现机制抽象了出来。

  • Jaeger-Collector 从 Jaeger Agent 接收 Trace,并通过一个处理管道对其进行处理。目前的管道会校验 Trace、建立索引、执行转换并最终进行存储。存储是一个可插入的组件,现在支持 elasticsearch、Cassandra 或 Kafka。

  • Jaeger-Query 服务会从存储中检索 Trace 并通过 UI 界面进行展现,该 UI 界面通过 React 技术实现。

注意:istio 中 Jaeger 还是个 all-in-one 的配置而且 span 都存在内存里,不能直接上生产,上生产还需要用 elasticsearch 等来持久化数据,还要对 Jaeger-collector 要收集 envoy 的请求数据,所以要开启 HPA 应对高并发场景。

在 Bookinfo 应用启动运行之后,连续访问20次,返回200为正常,会生成跟踪数据。

1
2
3
$ export GATEWAY_URL=$(kubectl -n istio-system get po -l istio=ingressgateway -o go-template='{{range .items}}{{.status.hostIP}}{{end}}')
$ export HTTP2_PORT=$(kubectl -n istio-system get svc istio-ingressgateway -o go-template='{{range .spec.ports}}{{if eq .name "http2"}}{{.nodePort}}{{end}}{{end}}')
$ for i in {1..20}; do curl -o /dev/null -s -w "%{http_code}\n" http://${GATEWAY_URL}:${HTTP2_PORT}/productpage; done

在 Jaeger dashboard 左侧版面中,从 Service 下拉列表中选择 productpage,点击 Find Traces 按钮,就会看到类似下图的内容:

点击第一条跟踪信息,这是最后一次刷新 /productpage 页面的信息。显示的内容会跟下图类似:

如上图所示,跟踪信息是由一系列的 Span 组成的,每个 Span 对应着 /productpage 请求过程中 Bookinfo 服务的调用。目标服务(右侧)的标签标识了每一行的耗时。第一行代表了外部调用到 productpage 服务的过程。istio-ingressgateway 是外部请求的入口。从图中我们可以看到,整个请求花费了 39.42 毫秒。在执行过程中,productpage 调用了 details 服务,消耗了 3.76 毫秒;接下来调用了 reviews 服务。reviews 服务消耗的了大概 15.89 毫秒。其中还包含了 reviews 对 ratings 服务所占用的 2.34 毫秒。

服务网格中是怎么实现的呢?

因为每个 Envoy Sidecar 代理了进出服务的所有流量,当有服务发起外部调用时,客户端(请求发起方) Envoy 会创建一个新的 span。一个 span 代表一组微服务之间的完整交互过程,从客户端发出请求开始到接收到服务端的响应为止。在服务交互过程中,客户端会记录请求的发起时间和响应的接收时间,服务器端Envoy 会记录请求的接收时间和响应的返回时间。

每个 Envoy 都会将自己的 span 视图信息发布到分布式追踪系统。当一个服务处理请求时,可能需要调用其他服务,从而导致因果关联的 span 的创建,形成完整的 trace。这就需要由应用来从请求消息中收集和转发下列 Header 在通信链路中的Envoy,可以截取、处理、转发相应的Header。

1
2
3
4
5
6
7
x-request-id
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
x-ot-span-context

比如我们看 productpage 这段创建span 在 HTTP 请求中获取 x-b3-*** 头部中的值:

details 也是获取头部的值:

SkyWalking

Apache SkyWalking ,它是一款优秀的国产 APM 工具,包括了分布式追踪、性能指标分析、应用和服务依赖分析等。从6.0.0开始也支持 Istio,他是通过 bypass Adapter 接入 Mixer 收集遥测数据进行分析,今后应用上了 Mesh 就不再需要植入 java 探针就可以通过 skywalking 来 tracing,实现代码无侵入。

最后的硬核广告 ———— Robotbot

Robotbot (火箭靴)是由 DaoCloud Labs 基于 VUE 框架,为 SkyWalking 贡献的开源 UI 项目,很酷炫很 fashion。

  • Dashboard:

  • Topology:

  • Trace:

总结

前面我们说过 Linkerd2.0 中,是由 proxy 暴露服务的 metrics,所有 Metrics 会被收集并存放在 prometheus 中,该 prometheus 实例专用来处理 Linkerd 生成的数据。
Istio 通过 Mixer 实现看起来复杂,但是自由度会更高,使得基础设施后端很灵活的接入 mesh。而且现在又有 Kiali 把原本分散的监控、分布式追踪,配置的查看都整合在了一起,功劳不小。日志还没讲,有时间还会继续扩充本文。