随着分布式架构逐渐成为主流,“可观测性”一词也日益频繁地被人提起,它涉及的范围比较广泛,主要概括为如下三类:
聚合度量(metrics)事件日志(logging)链路追踪(tracing)这三个方向虽然各有千秋,各有侧重,但是又不完全独立。在Peter Bourgon 的文章《Metrics, Tracing, and Logging》系统地阐述了这三者的定义、特征,以及它们之间的关系与差异,受到了业界的广泛认可。
(相关资料图)
在实际的工作中,大家或多或少对上面三种都有一定的了解,只是没有机会或者没有需求去深入研究。
聚合度量(Metrics)度量是一种计量单位,它是指对系统中某一指标的统计聚合,然后通过聚合信息来揭示系统整体的运行状况。
度量总体上可分为客户端的指标收集、服务端的存储查询以及终端的监控预警三个相对独立的过程,每个过程一般都是不同的组件来完成,以Prometheus为例:
指标可以通过直接抓取各种exporters,也可以从pushgateway抓取,然后存储在TSDB(时序数据库)中,查询指标可以通过grafana,也可以通过prometheus web,报警则是通过altermanager实现。
可以看到,一个度量工具的内部实现是很复杂的,在使用的时候也会损耗一定的资源。
目前来说,在云原生领域中,Prometheus占据了很大的主导地位,严格来说,它已经成云原生监控的标配,下面我主要以Prometheus为例进行介绍。
指标收集指标收集主要包括两部分:
指标定义指标收集相比于收集,指标定义尤为重要,良好的指标定义可以更直观的反应系统状态。
最常用的黄金指标有:
延迟:延迟是信息的发送方和接收方之间的时间延迟,以毫秒(ms)为单位。其原因通常是由于数据包丢失、网络拥塞和称为 “数据包延迟差异” 的网络抖动。延迟直接影响客户体验,转化为成功请求的延迟和失败请求的延迟。流量:流量是系统上完成的工作量所带来的压力。它通过每秒查询数 (QPS) 或每秒事务数 (TPS) 来衡量。企业通过数量来衡量这一点:关键绩效指标 (KPI) 是在给定时间访问网站的人数。这是与商业价值的直接关系。错误:错误是根据整个系统中发生的错误来衡量的。什么被视为服务错误率的重要指标!有两类错误,显式错误,例如失败的 HTTP 请求(例如,500 个错误代码)。而一个隐含的错误将是一个成功的响应,但与错误的内容或响应时间长。饱和度:饱和度定义了服务的过载程度。它衡量系统利用率,强调资源和服务的整体能力。这通常适用于 CPU 使用率、内存使用率、磁盘容量和每秒操作数等资源。仪表板和监控告警是帮助您密切关注这些资源并帮助您在容量变得饱和之前主动调整容量的理想工具。利用率:虽然不是 “四大金信号” 的一部分,但值得一提;利用率告诉资源或系统有多忙。它以 %(百分比)表示,范围为 0–100%。所以在做指标定义的时候,可以结合以上的黄金指标进行分类,但是并不代表每一种类型的应用都需要满足以上所有指标。以系统监控为例,如下表示是否需要监控该类指标:
定义好资源指标后,再来定义指标具体的获取方法。
目前,基于Prometheus监控所实现的Exporter非常多,这些Exporter基本能够拿到我们想要的指标,比如:
指标查询指标收集到Prometheus之后,会存储到它的TSDB(时序数据库)中,我们可以在Prometheus Web中查询需要的指标,如下获取不同时间节点kubelet的HTTP请求总数:
监控预警指标度量是手段,最终目的是做分析和预警。
我们可以通过这些指标制作监控大屏,随时观察系统的状态,如下可以实时监控Kubernetes中容器以及节点的状态:
良好的可视化能力对于提升度量系统的产品力十分重要,长期趋势分析(譬如根据对磁盘增长趋势的观察判断什么时候需要扩容)、对照分析(譬如版本升级后对比新旧版本的性能、资源消耗等方面的差异)、故障分析(不仅从日志、追踪自底向上可以分析故障,高维度的度量指标也可能自顶向下寻找到问题的端倪)等分析工作,既需要度量指标的持续收集、统计,往往还需要对数据进行可视化,才能让人更容易地从数据中挖掘规律。
还可以对重要的指标进行告警,以便维护人员能够及时地介入排查问题,如下是一个应用JVM使用过载的告警。
但是,在做告警的时候需要综合考虑指标的重要程度,不是所有指标都需要告警,不然就容易造成告警风暴,最后就会真实演绎《狼来了》的故事。
事件日志(Logging)日志用来记录系统运行期间所发生的事件,每个系统都应该有日志。
日志是排查问题的重要手段,大部分系统问题最终都会追溯到日志上,所以良好的日志记录有助于快速定位系统问题。
但是,目前基本都是微服务多节点的形式存在,没办法像单机时代那样简单使用命令就能获取到日志内容。而是需要把日志收集到专门的日志系统,然后再进行查询、分析等。
目前比较受欢迎的开源日志系统是ELK或者EFK,它在日志领域有着不可撼动的地位。
事件日志也涉及以下几个方面:
日志输出日志收集日志查询日志告警日志输出一千个开发可能有一千个日志输出方式,而且输出的内容千奇百怪,不管重要的或者不重要的都输出到日志里,这将会导致日志查看困难,干扰大。
所以,良好的日志记录习惯是非常重要的,在企业中应该有专门的日志规范,这样可以统一格式、统一标准,不仅有助于收集,也有助于查看。
打印日志应该尽量做到以下几点:
记录请求的TraceID记录关键事件,包括上下文不要打印敏感信息合理规划日志级别日志收集对于分布式服务,为了能同时看到跨节点的全部日志,就需要把各种日志统一收集,比如使用Logstash或者Filebeat来收集日志,在日志收集的同时还可以对日志进行处理,比如同一个应用的日志可以建一条索引,同一个应用的索引可以按天进行创建等,这样避免索引过大导致查询困难等问题。
如果在日志收集的过程中发现日志比较大,可以在收集处理的过程中先把日志写入缓存或者消息队列,避免直接写入Elasticsearch导致其压力过载。
日志查询收集到的日志最终是存储在Elasticsearch中,它通常搭配Kibana一起使用,方便用户操作。
Kibana 尽管只负责图形界面和展示,但它提供的能力远不止让你能在界面上执行 Elasticsearch 的查询那么简单。Kibana 宣传的核心能力是“探索数据并可视化”,即把存储在 Elasticsearch 中的数据被检索、聚合、统计后,定制形成各种图形、表格、指标、统计,以此观察系统的运行状态,找出日志事件中潜藏的规律和隐患。按 Kibana 官方的宣传语来说就是“一张图片胜过千万行日志”。
日志告警在做日志输出的时候,对于一些有破坏性的日志需要特别标记,当遇到这类日志就需要及时的通知维护人员。我们可以使用ElastAlert来进行告警处理。
ElastAlert是三方插件,通过查询 ElasticSearch 中的记录进行比对,通过配置报警规则对匹配规则的日志进行警报。 ElastAlert 将Elasticsearch与两种类型的组件(规则类型和警报)结合使用,定期查询Elasticsearch,并将数据传递到规则类型,该规则类型确定何时找到匹配项。发生匹配时,将为该警报提供一个或多个警报,这些警报将根据匹配采取行动。
链路追踪(Tracing)有了度量和日志,在多数情况下已经能满足日常使用,但是它们有一个弊端,就是没办法很直观的查看上下文,也无法有效的追踪某个请求。
所以,就引入了链路追踪。
从目标来看,链路追踪的目的是为排查故障和分析性能提供数据支持,系统对外提供服务的过程中,持续地接受请求并处理响应,同时持续地生成 Trace,按次序整理好 Trace 中每一个 Span 所记录的调用关系,便能绘制出一幅系统的服务调用拓扑图。根据拓扑图中 Span 记录的时间信息和响应结果(正常或异常返回)就可以定位到缓慢或者出错的服务;将 Trace 与历史记录进行对比统计,就可以从系统整体层面分析服务性能,定位性能优化的目标。
从字面上看链路监控的实现方式比较简单,然而在实际工作中却比较复杂。主要在于企业业务系统可能采用不同的程序语言 ,每一种程序语言实现的方式都不一样,这就导致工作量非常巨大,而且还要考虑以下几点:
低损耗:如果接入链路监控不仅没有解决问题,反而加大了性能开销,这就得不偿失。透明:尽量在不加大开发工作量,最好能做到无侵入接入。易用:傻瓜式的使用方式比较受欢迎。目前最常用的是Zipkin、Skywalking、Pinpoint等,它们都是基于服务追踪实现的。
服务追踪的实现思路是通过某些手段给目标应用注入追踪探针(Probe),针对 Java 应用一般就是通过 Java Agent 注入的。探针在结构上可视为一个寄生在目标服务身上的小型微服务系统,它一般会有自己专用的服务注册、心跳检测等功能,有专门的数据收集协议,把从目标系统中监控得到的服务调用信息,通过另一次独立的 HTTP 或者 RPC 请求发送给追踪系统。
下面是使用Skywalking收集之后的查询页面。
最后可观测性平台是一个很大很复杂的平台,大部门公司都是用一些开源手段来堆叠,虽然能解决一些问题,但是它们各自是相互独立的,没办法很友好的进行关联。这也导致在排查问题的时候需要各个平台来回切换,而且每个平台都需要一定的学习成本,这也导致许多公司安装部署了,但是实际很少去用,没有发挥其要实现的效果。
链接【1】https://peter.bourgon.org/blog/2017/02/21/metrics-tracing-and-logging.html【2】https://skywalking.apache.org/【3】https://www.elastic.co/cn/