全书目录
- 第一章 概述
- 第二章 安装
- 第三章 流控
- 第四章 服务弹性
- 第五章 混沌测试
本文目录
第6章 可观测性
6.1 分布式调用链跟踪(tracing)
6.1.1 基本概念
6.1.2 Jaeger
6.1.3 Istio对分布式调用跟踪的支持
6.2 遥测(Metric)
6.3 服务图(Service graph)
第6章 可观测性
微服务架构管理中最大的挑战之一是如何通过简单方法就能了解系统各个组件之间的关系。终端用户的一次会话可能会流经多个甚至几十个独立部署的微服务,因此,发现哪里有性能瓶颈或错误变得尤为重要。
本章中,我们会通过Jaeger实现调用链跟踪、通过Grafana和Prometheus实现遥测数据收集和展示,通过Kiali生成服务可视化图。
Istio的Mixer模块由istio-policy和istio-telemetry服务组成,运行在istio-system命名空间的两个独立的pod中。下面的命令能很容易地将它们找出来,因为它们都带有同样的标签:
代码语言:javascript复制 oc get pods -l istio=mixer -n istio-system
oc get services -l istio=mixer -n istio-system
6.1 分布式调用链跟踪(tracing)
通常,了解微服务系统架构所做的第一件事情就是看那些服务参与了终端用户会话。当多个团队部署了大量互相独立的微服务时,要理解它们之间的依赖会非常困难。Istio的Mixer模块带有开箱即用的能力,从分布式服务中获取跟踪跨度(tracing span)。这意味着跟踪功能是与编程语言无关的,因此使用不同语言进行编程的团队都可以使用它。
6.1.1 基本概念
分布式调用链跟踪这概念起源于Google发表的论文《Dapper,大规模分布式系统的跟踪系统》。它具有以下几个核心概念。
OpenTracing:是CNCF(云原生计算基金会)下的一个项目,其中包含了一套分布式调用跟踪的标准规范、各种语言的API、编程框架和函数库。其目的是定义一套分布式调用跟踪的标准,以统一各种分布式调用跟踪的实现。目前已有大量支持OpenTracing规范的跟踪程序(Tracer),包括Jaeger和Zipkin等。在微服务应用中采用OpenTracing API实现分布式调用各种,可以避免供应商锁定,从而以最小的代价和任何兼容OpenTracing的基础设施对接。
跨度(span):是两个服务之间的一次请求与响应过程,比如一次REST调用或者数据库操作。Jaeger将其定义为“系统中的一个逻辑的交互单元,具有操作名称(operation time)、操作开始时间(start timestamp)和结束时间(finish timestamp)”。跨度是分布式调用跟踪的最小跟踪单位。
调用链(trace):是分布式系统中的一个端到端事务,Jaeger将其定义为“数据或执行穿过系统的路径,可视为跨度的有向无环图”。
跨度上下文(Span context):这是分布式调用跟踪的上下文信息,包括Trace ID,Span ID以及其它需要传递到下游服务的内容。一个OpenTracing的实现需要将跨度上下文通过某种序列化机制在进程边界上进行传递,以将不同进程中的跨度关联到一个调用链上。在基于HTTP协议的分布式调用中,通常使用HTTP Header来传递跨度上下文信息。Zipkin使用b3 HTTP Header,Jaeger使用 uber-trace-id HTTP Header。Istio/Envoy支持b3 HTTP Header和x-ot-context Header。
跨度的数据结构中主要包括以下内容:
- Name:Span所代表的操作名称,例如REST接口对应的资源名称。
- Start timestamp:Span所代表操作的开始时间
- Finish timestamp:Span所代表的操作的的结束时间
- Tags:一系列标签,每个标签由一个键值对组成。该标签可以是任何有利于调用链分析的信息,例如方法名,URL等。
- SpanContext:用于跨进程边界传递Span相关信息,在进行传递时需要结合一种序列化协议使用。
- References:该Span引用的其它关联Span,主要有两种引用关系,Childof和FollowsFrom。
o Childof: 最常用的一种引用关系,表示Parent Span和Child Span之间存在直接的依赖关系。例PRC服务端Span和RPC客户端Span,或者数据库SQL插入Span和ORM Save动作Span之间的关系。
o FollowsFrom:如果Parent Span并不依赖Child Span的执行结果,则可以用FollowsFrom表示。例如网上商店购物付款后会向用户发一个邮件通知,但无论邮件通知是否发送成功,都不影响付款成功的状态,这种情况则适用于用FollowsFrom表示。
一条调用链(trace)可被认为是一个由多个跨度(span)组成的有向无环图,多个跨度组成一个请求的完整调用链。而分布式跟踪系统要实现的,就是记录每次发送和接受动作的标识符和时间戳,将一次请求涉及到的所有服务串联起来,只有这样才能搞清楚一次请求的完整调用链。图6-1是一个分布式调用的例子,客户端发起请求,请求首先到达负载均衡器(load balancer),接着经过认证(auth)服务,计费(billing)服务,然后请求资源(resource),最后返回结果。
图6-1. 一个分布式调用示例
分布式跟踪系统负责采集和存储调用链数据,然后通常会使用包含时间轴的时序图来将这个调用链展现出来,横坐标是时间,圆角矩阵是请求的各个执行阶段,如图6-2所示。
图6-2. 分布式跟踪系统生成的时序图
6.1.2 Jaeger
Jaeger是Uber推出的一款开源分布式跟踪系统,兼容OpenTracing API,于2017年9月加入CNCF基金会,其架构如图6-3所示。
图6-3. Jaeger架构
Jaeger 主要由以下几部分组成:
- Client – Jaeger的客户端,实现了符合OpenTracing API标准的SDK,支持主流编程语言。客户端直接集成在应用代码中,应用程序通过其API写入数据,客户端库把调用链信息按照应用程序指定的采样策略传递给Agent。在应用中调用Jaeger Client库记录跨度的过程通常被称为埋点。
- Agent - 它是一个监听在UDP端口上接收跨度数据的网络守护进程,它会将数据批量发送给Collector。它被设计成一个基础组件,部署在宿主机上。Agent将Client 库和Collector 解耦,为Client库屏蔽了路由和发现Collector的细节。
- Collector - 接收Agent发送来的数据,然后将数据写入后端存储。Collector被设计成无状态的组件,因此您可以同时运行任意数量的Collector。
- Data Store - 后端存储被设计成一个可插拔的组件,支持将数据写入Cassandra和Elastic search。
- Query - 接收查询请求,然后从后端存储系统中检索调用链并通过UI进行展示。Query 是无状态的,您可以启动多个实例,把它们部署在Nginx这样的负载均衡器后面。
6.1.3 对分布式调用跟踪的支持
Istio利用Envoy的分布式调用跟踪功能来为网格中的应用提供开箱即用的跟踪能力。Istio支持接入多种跟踪后端系统(tracing backend),包括Zipkin、Jaege和LightStep。Istio支持与分布式跟踪系统的两种整合方式:
- 基于Envoy的整合(Envoy-based)
- 基于Mixer的整合(Mixer-based)
Istio支持与LightStep、Zipkin以及与Zipkin API相兼容的后端比如Jaeger进行基于Envoy的整合。在这种整合中,Envoy边车代理直接向后端跟踪系统发送跟踪信息。它负责:
- 为每个流经它的请求产生请求ID(request ID)和跟踪头(trace headers,比如x3-B3-TraceID)
- 为每个流经它的请求根据请求及其响应的元数据产生跟踪跨度
- 发送所产生的跟踪跨度信息到跟踪后端
- 转发跟踪头给被代理的应用
以请求ID为例,Envoy使用x-request-id头去唯一地定位一个请求,并为它做日志和跟踪。Envoy会为每个从外部进入网格的请求产生x-request-id并放到HTTP头中,也会为不带有此信息的内部请求产生此ID。
Istio还支持以基于Mixer的方式与某些跟踪后端进行整合,比如Stackdriver。在这种方式中,Envoy负责为每个流经它的请求产生请求ID和跟踪头(比如x3-B3-TraceID),并异步发送给Mixer,同时转发跟踪头给被代理的应用;Mixer则负责为每个请求产生跟踪跨度数据,并把这些数据发给所配置的跟踪后端。
尽管Envoy能够自动产生跟踪信息,它还是要依赖应用将跟踪头信息传递给后续请求。在应用中,应用需要从进来的请求中获取以下信息并传递到出去的请求中:
· x-request-id
· x-b3-traceid
· x-b3-spanid
· x-b3-parentspanid
· x-b3-sampled
· x-b3-flags
· x-ot-span-context
对于某些应用,如果所选择的框架支持自动传递这些HTTP头,那么就不用显式传递跟踪上下文了。比如,Spring Boot框架在github中有个开源项目https://github.com/opentracing-contrib/java-spring-cloud ,能支持自动跟踪。我们customer和preference示例程序使用符合OpenTracing标准的TracerResolver库(https://github.com/jaegertracing/jaeger-client-java/tree/master/jaeger-tracerresolver),它会被自动加载。
在笔者的测试环境中,Istio采用基于Envoy的方式与后端跟踪系统Jaeger整合。Jaeger的服务和pod名称为istio-tracing,采用的Jaeger镜像是docker.io/jaegertracing/all-in-one,它包含jaeger-agent、jaeger-collector和jaeger-query这三个组件。其中,Envoy代理被配置为自动地将跟踪信息发送到jaeger-collector服务,jaeger-collector负责将跟踪数据写入存储卷。要注意的是,这个存储卷采用的是pod所在宿主机上的临时文件夹。因此,当istio-tracing这个pod被重建后,所保存的数据都会丢失。因此,在生产系统中,要考虑使用持久存储来保存数据。
运行下面的命令来打开Jaeger界面:
代码语言:javascript复制 minishift openshift service tracing --in-browser
你可以从下拉列表中选择customer服务,再展开所产生的跟踪,如图6-4所示:
图6-4. Jager中的customer-preference-recommendation跟踪的展示
Istio能为所有流经网格的请求产生跟踪信息。这在开发阶段会很有用,能帮助你进行充分的调试;但是在某些时候,比如性能测试时或在生产系统中,这会对系统性能带来一定压力,而且数量庞大的数据也会占用大量存储空间。为了解决这个问题,Jaeger支持设置采样率。采样率通过Istio Pilot的“PILOT_TRACING_SAMPLING”环境变量进行配置。当PILOT_TRACING_SAMPLING的值为100时,表示全采样,也就是每一次请求都会采样;当PILOT_TRACING_SAMPLING值为50时,表示1/2采样,也就是每两次请求会采样一次。Istio中的PILOT_TRACING_SAMPLING的默认值为1,表示每100个请求采样一次。具体请查阅Jaeger官方文档。可通过下面的命令进行查看或修改:
代码语言:javascript复制 oc edit deployment istio-pilot -n istio-system
6.2 遥测(Metric)
Istio的另一个核心功能是网络流量的可观测性。因为网格内服务间的所有流量都会经过Envoy代理,Istio的控制平面就能从这些代理收集日志和指标,从而让你可深入地了解网格的状况。Istio控制平面中的一组件为Mixer,其在K8S中有两个独立的部署,一个是istio-policy,另一个是istio-telemetry。前者提供控制策略,后者提供遥测数据收集。
Istio网格中的每个pod中都会有一个Envoy代理,它负责在发出每个请求前调用istio-policy来检查前置条件,并在请求结束后调用istio-telemetry来发送遥测数据。为提高性能,Envoy代理会在本地缓存策略和遥测数据,以减少调用Mixer的次数。Mixer可配置多种后端,其中Metric后端负责接收遥测数据。在Istio部署中,通常会使用Prometheus来作为遥测后端。Prometheus(普罗米修斯)是一款开源弹性监控解决方案,它将其数据存储至时序数据库,且提供了多维度的数据模型、强大的查询语言和简单的面板来生成被监控资源的报表。
图6-5. Mixer及其各种后端
默认地,Isito会利用Prometheus和Grafana来存储和展示服务网格中的测量数据。在Istio的默认部署中会部署Prometheus和Grafana服务,并做了基本配置,添加了若干度量指标,使得基本遥测数据能被收集到和展示出来。通过Istio提供的CRD,还能自定义度量指标,并使得它们被自动地收集到。Grafana是一款开源数据可视化看板,可指定多个数据源执行查询,将枯燥的数据转化为多维度的面板。Isito中的Grafana将Prometheus作为其数据源,提供了多个为Istio定制的面板(Dashboard),能从多个维度展示Istio服务网格的状态。遥测数据收集过程所涉及的服务之间的基本交互过程如图6-6所示,包括以下几个主要步骤:
- Envoy代理将每个请求的属性异步地报告给Mixer的istio-telemetry服务
- Mixer根据所配置的后端Prometheus的要求对这些属性进行格式转换
- Mixer将转换后的数据发给Prometheus
- Prometheus处理和存储遥测数据
- 用户通过Prometheus GUI或Grafana GUI查看遥测数据
图6-6. 有关服务之间的基本交互流程
运行下面的命令可直接在浏览器中打开Prometheus面板:
代码语言:javascript复制 minishift openshift service prometheus --in-browser
在Prometheus面板中,你可以自定义测量项并图形化结果。比如,你可以查看recommendation服务的v2版本的总请求数,如图6-7所示:
代码语言:javascript复制 istio_requests_total{destination_app="recommendation", destination_version="v2"}
图6-7.Prometheus面板
你还可以查看pod的内存使用量:
代码语言:javascript复制 container_memory_rss{container_name="customer"}
Prometheus是一个非常强大的从Kubernetes/OpenShift集群中收集和展现测量数据的工具。目前它是CNCF联盟中顶级的已毕业项目之一。关于它的更多信息,请访问Prometheus官网。
运行下面的命令去获得Grafana界面的URL:
代码语言:javascript复制 minishift openshift service grafana --url
在Grafana面板左上侧选择Istio Workload Dashboard,如图6-8所示:
图6-8. Grafana中的Istio Workload 面板
6.3 服务图(Service graph)
早期Istio就提供了开箱即用的基本的服务图形化功能。现在,Istio有了一个新的功能更全面的服务图形化工具和总体监控监控方案,那就是由红帽团队创建的Kiali,如图6-9所示。Kiali项目为一些有趣的问题提供了答案:我的Istio服务网格中有哪些微服务?它们之间是如何连接的?
本书写作时,Kiali还需要被单独安装,安装步骤还比较复杂。Kiali需要知道Jaeger和Granfana的URL,并需被设置给一些环境变量。Kiali安装步骤如下:
代码语言:javascript复制 # URLS for Jaeger and Grafana
export JAEGER_URL="https://tracing-istio-system.$(minishift ip).nip.io"
export GRAFANA_URL="https://grafana-istio-system.$(minishift
ip).nip.io"
export IMAGE_VERSION="v0.10.0"
curl -L http://git.io/getLatestKiali | bash
如果安装时碰到问题,请访问Kiali用户论坛https://groups.google.com/forum/#!forum/kiali-users。象Istio一样,Kiali也是一个快速发展中的项目。它的主菜单和Graph面板如图6-9所示。
图6-9. Kiali面板
Kiali的架构如图6-10所示。它包括两个组件Kiali front-end和Kiali back-end。前者用于界面展示,它从Kiali back-end获取数据并展现给用户;后者和Istio通信,获取和处理数据,并将数据通过Kiali front-end展现给用户。Kiali依赖于Istio,它通过底层平台API和Prometheus获取Istio的数据和配置。当前Kiali支持OKD和Kubernetes,利用它们的API去获得集群和服务网格的配置,比如命名空间、服务、部署等等。Kiali直接与Prometheus通信,使用保存在Prometheus中的数据,计算出服务网格的拓扑结构,展示遥测数据,计算健康状态以及展示存在的问题等。
图6-10. Kiali架构
Kiali还可以与Grafana集成,在其Workload界面中添加View in Granfana链接,点击后直接跳转至Grafana界面,展示该应用的遥测数据,如图6-11所示。
图6-11. 在Kiali中集成Grafana链接
Kiali还可以与Jaeger集成,在其页面中可以直接查看服务的分布式调用跟踪信息,如图6-12所示。具体配置方法请查阅https://kiali.io/documentation/distributed-tracing/。
图12. 在Kiali中查询服务的分布式调用跟踪信息
在Istio中,Kiali与Grafana和Jaeger的集成,是在ConfigMap kiali中配置的。它会被挂载到kiali pod中,成为kiali的配置文件/kiali-configuration/config.yaml。在译者的环境中,其内容如下:
代码语言:javascript复制istio_namespace: istio-system
auth:
strategy: login
server:
port: 20001
web_root: /kiali
external_services:
tracing:
in_cluster_url: http://tracing.istio-system/jaeger
url: http://tracing-istio-system.router.default.svc.cluster.local/jaeger
grafana:
url: http://grafana-istio-system.router.default.svc.cluster.local
prometheus:
url: http://prometheus:9090
本章中,你已经看到了好几个开箱即用的工具和第三方工具,Istio使得你的应用的各个微服务组件变得越来越可视和可观测。在前面章节中介绍了如何引入错误和网络延迟,现在,通过这些工具,你就能更好地跟踪问题在哪里了。
书籍英文版下载链接为 https://developers.redhat.com/books/introducing-istio-service-mesh-microservices/,作者 Burr Sutter 和 Christian Posta。
本中文译稿版权由本人所有。水平有限,错误肯定是有的,还请海涵。