第11章 让服务更易观测与监控

上一章

11.2 指标收集

下一章

更多图书

11.1 整体介绍

为了获取服务运行时的行为,可观测性很有必要。为了让服务更易观测,我们需要收集服务的日志(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