为了获取服务运行时的行为,可观测性很有必要。为了让服务更易观测,我们需要收集服务的日志(logging),统计服务的运行指标数据(metrics),记录服务的调用链追踪(tracing)。这三者都有互有重叠的功能部分,关系如图11-1所示。
图11-1 服务的日志、指标数据、调用链追踪之间的关系(图片来源:Peter Bourgon的文章“Metrics,tracing,and logging”)
日志是事件驱动的并根据时间变化不断存储的不可变数据。日志一般有如下几种格式:
·纯文本:这是最常用的日志格式。
·结构化数据:一般使用JSON格式存储。
·二进制:一般是为节省空间或有特殊用途的格式,比如:MySQL的二进制日志等。
一般会将日志收集到一个集中的日志中心,用于存储、搜索和分析。通常情况下使用开源的日志收集处理技术栈是个不错的选择。比如开源的ELK/EFK日志系统。
指标数据是指一段时间内对系统的测量数值,是一段时间内数据的聚合。通过指标数据通常可以计算出一段时间内的平均值、最大值和最小值,可以了解数据在某段时间内的变化趋势,指标数据占用的存储空间一般也会比日志系统小得多,大多数的监控系统都是基于指标数据做出来的,我们可以聚合多个指标数据组成一个监控面板,观测过去某段时间内数据的变化。监控面板一般有如下几种类型:
·计数器(Counter):只可以增加不可以减少,一个简单的计数功能。例如:统计请求次数。
·仪表盘(Gauge):可以增加也可以减少,仪表盘只代表当前的数据状态。例如:统计CPU使用率。
·柱状图(Histogram):用于统计一些数据的分布情况,计算在一定范围内的分布情况。例如:统计一段时间内响应时间大于某个数值的请求数。
·概要(Summary):与柱状图类似,计算一段时间内指标对象总数以及指标的总和,提供百分位的功能。例如:请求响应时间的99百分位。
通过指标数据,我们可以了解一段时间内整体数据的变化情况。收集指标数据的工具现在比较多,例如Prometheus、Influxdb、Grafana,可用于指标数据的可视化。
调用链追踪是请求级别的数据记录,包含系统中一个请求在生命周期内所涉及的所有数据的集合。比如:调用远程服务的耗时,查询数据库时所用的SQL语句等。一般情况下,调用链涉及从请求进入服务到服务响应数据的所有调用过程。调用链系统会在请求进入服务时生成唯一的请求ID,这个ID会一直传递给将要调用的其他服务,直到本次调用成功或者失败,调用链系统会记录每一次调用的耗时等信息。方便查看一个请求的完整调用过程。调用链有如下几个重要概念:
·Span:是服务调用信息的存储单位,每一次服务调用就会生成一个Span用于存储本次服务调用的信息。
·Trace:请求的整个服务调用链,包含多个Span。
Trace与Span的关系如图11-2所示。
通过调用链追踪,我们能清楚地知道一个用户请求在整个系统的服务调用情况,知道每一个请求的每一个调用的耗时,看到系统中真实的服务调用情况,在OpenTracing组织的努力下,服务调用链追踪有了统一的标准。调用链追踪可以使用Jaeger、Zipkin等来收集、存储、查看和分析。
图11-2 Trace与Span的关系
日志、指标数据与调用链并不是孤立存在的,可以配合使用来更好地排查服务的问题。当我们观测到服务指标数据出现问题时,可以通过调用链来查看服务的调用情况,找到调用链上有问题的服务,然后再配合日志找到服务的具体问题。例如:当我们收到监控系统的报警提示服务A调用耗时过长,我们可以通过调用链追踪系统,找到服务调用链上响应时间过长的是服务B,然后通过日志系统,搜索服务B的相关日志,进而找到问题的原因,修复服务B的问题,最终解决服务指标异常的问题。
【实验前的准备】
进行本章实验前,需要先执行如下的前置步骤。
1)部署Istio的官方示例完整功能版本:
#配置 $ cp /usr/local/istio/install/kubernetes/istio-demo.yaml /usr/local/istio/install/kubernetes/istio-demo.yaml.ori $ sed -i 's@2048Mi@500Mi@g' /usr/local/istio/install/kubernetes/istio-demo.yaml $ sed -i 's@quay.io/coreos/hyperkube:v1.7.6_coreos.0@registry.cn-shanghai.aliyuncs.com/gcr-k8s/hyperkube:v1.7.6_coreos.0@g' /usr/local/istio/install/kubernetes/istio-demo.yaml #部署 $ kubectl apply -f /usr/local/istio/install/kubernetes/helm/istio/templates/crds.yaml $ kubectl apply -f /usr/local/istio/install/kubernetes/istio-demo.yaml #查看状态 $ kubectl get svc -n istio-system $ kubectl get pod -n istio-system
等待所有pod启动完成,再进行后续的实验步骤。
2)下载实验时用到的源码仓库:
$ sudo yum install -y git $ git clone https://github.com/mgxian/istio-lab Cloning into 'istio-lab'... remote: Enumerating objects: 247, done. remote: Counting objects: 100% (247/247), done. remote: Compressing objects: 100% (173/173), done. remote: Total 774 (delta 153), reused 164 (delta 73), pack-reused 527 Receiving objects: 100% (774/774), 283.00 KiB | 229.00 KiB/s, done. Resolving deltas: 100% (447/447), done. $ cd istio-lab
3)开启default命名空间的自动注入功能:
$ kubectl label namespace default istio-injection=enabled namespace/default labeled
4)部署用于测试的服务:
$ kubectl apply -f service/go/service-go.yaml $ kubectl apply -f service/node/service-node.yaml $ kubectl apply -f service/lua/service-lua.yaml $ kubectl apply -f service/python/service-python.yaml $ kubectl apply -f service/js/service-js.yaml $ kubectl get pod NAME READY STATUS RESTARTS AGE service-go-v1-7cc5c6f574-chmc4 2/2 Running 0 3m43s service-go-v2-7656dcc478-kqwg5 2/2 Running 0 3m43s service-js-v1-55756d577-qvkkn 2/2 Running 0 3m36s service-js-v2-86bdfc86d9-hhhs8 2/2 Running 0 3m36s service-lua-v1-5c9bcb7778-n5l5t 2/2 Running 0 3m41s service-lua-v2-75cb5cdf8-bv7kp 2/2 Running 0 3m40s service-node-v1-d44b9bf7b-5qsnq 2/2 Running 0 3m42s service-node-v2-86545d9796-tg5vx 2/2 Running 0 3m42s service-python-v1-79fc5849fd-kt7ls 2/2 Running 0 3m39s service-python-v2-7b6864b96b-4hln6 2/2 Running 0 3m39s