云原生大厦的基石之一「云原生可观测性」
01 云原生概述
云原生的概念近几年非常火热 🔥,而且它极有可能成为 IT 技术新的发展方向 🚩, 本文将一探云原生。
在介绍云原生的概念之前,我们先理解一下当下面向机器开发的软件系统。不管是运行在 Windows 或者 Linux 上的 PC 端应用,还是运行在 Android 或者 IOS 上的移动端应用,这些应用的定义都是面向将来部署的机器的,需要考虑设备上的系统资源和环境。
而在云原生中,开发者无需考虑底层的技术实现,只需要关注充分发挥云平台的弹性和分布式优势,实现应用的快速部署、按需伸缩、不停机交付等。
那么到底什么是云原生呢 ❓
被广泛沿用至今的云原生概念是由 Pivotal 公司的 Matt Stine 在 2013 年首次提出的:云原生(Cloud Native)
代表的是一种构建和运行应用程序的技术和方法论,其中云(Cloud)
表示的是应用运行在云基础设施之上;原生(Native)
则强调的是应用从设计之初就是基于云基础设施能力的,借助云的优势实现更加高效强大的技术架构。
2017年,Matt Stine 又将 ➡️ 云原生特征 ⬅️ 重新归纳为六大点,分别是:
- 模块化 Modularity
- 可观测性 Observability ☑️
- 可部署性 Deployability
- 可测试性 Testability
- 可处理性 Disposability
- 可替换性 Replaceability
作为六大特征之一的可观测性是保证云原生应用稳定性的基础。在云原生时代,应用规模不断扩大,复杂度愈来愈高,而其中潜藏的问题和风险也随之增多。这对应用的稳定性提出了更高的要求,它需要能够支撑业务的快速迭代、要能具备快速的故障响应能力、要能适应微服务复杂的调用拓扑、要能保证高效的运维协同。
总的来说,可观测性是云原生行稳致远的根本保障 ❗️
02 什么是可观测性
2.1 可观测性的含义
可观测性并不是从无到有的概念,它是从传统的软件监控发展而来的。但是传统监控更多的是从运维的角度出发,基于传统的监控指标,从系统外部视角去观察系统发生了什么 👀 。
进入云原生时代后,应用的构建部署与运行时基础设施都发生翻天覆地的变化 🐎🐎🐎:技术架构微服务化、运行时环境容器化、业务系统依赖关系复杂化,运行实例生命周期短,规模大;服务自动注册发现,监控也随着实时动态调整,传统的监控方式已经无法满足云原生的场景。
可观测性概念的提出就是为了解决这一问题,可观测性是从系统内部出发,基于白盒化 🌝 的思路去监测系统内部的运行情况。可观测性贯穿应用开发的整个声明周期,通过分析应用的指标、日志和链路
等数据,构建完整的观测模型,从而实现故障诊断、根因分析和快速恢复。
2.2 传统监控与可观测性
可观测性虽然由传统监控发展而来,但是他们又有着本质的不同 🌓,在本节我们进一步讨论这两者的差异。
传统监控更多的是指运维自动化工具,主要用途是替代人自动监控系统运行情况,在系统发生异常时告警,最终还是需要人工 👷 去分析异常、故障诊断和根因分析。
而可观测性不仅包含传统监控的能力,更多的是面向业务,强调将业务全过程透明化
的理念。可观测性贯穿业务的全生命周期,实现从底层云基础设施、通用技术组件到业务应用系统的全景监控、智能运维和自修复能力等体系化的服务能力 💪💪。
更直观的如下图所示,可观测性比传统监控有着更加丰富的内涵。(图片来源,如有侵权请告知)
传统监控与可观测性的具体区别有:
传统监控 | 可观测性 | |
---|---|---|
监控对象 | 资源监控,主要监控基础设施 | 全景监控,监控基础设施、中间件和调用链等 |
关注点 | 聚焦与发现问题 | 注重发现问题根本原因 |
监控视角 | 黑盒监控,从外部视角看系统运行状态 | 白盒监控,由内而外看系统运行状态 |
数据基础 | 仅以指标数据为依据 | 指标、日志、链路 |
实践方式 | Ops为主,后期追加 | DevOps,全生命周期 |
面向用户 | 面向运维工程师 | 面向开发和运维工程师 |
最后,用大牛 😎 的一句话总结传统监控与可观测性的区别:✨ “监控告诉我们系统的哪些部分是工作的;可观测性告诉我们那里为什么不工作了。” ✨
03 可观测性的原理
3.1 可观测性的数据基础
在云原生中,可观测性的实现依赖于监控指标 / 监控度量(Metrics)、事件日志(Logs)和链路追踪(Traces)三种数据。这三种数据各有侧重,但又不是完全独立,它们天然就有重合或者可以结合之处。📄《Metrics, Tracing, and Logging》📄 一文中总结了这三者的定义和特征,以及它们之间的关系与差异,并得到了广泛认可 💯。
监控指标(Metrics)、事件日志(Logs)和链路追踪(Traces)三种数据关系与差异入上图所示,下面我们具体了解一下每一种数据的含义:
- 1️⃣ 监控指标(Metrics):度量是指对系统中某一类信息的统计聚合,存储空间很小,可以观察系统的状态和趋势。度量的主要目的是监控(Monitoring)和预警(Alert),监控主要是底层基础资源运行状态的数据,通过多维度聚合、分析和可视化展示,帮助快速理解系统资源的运行状态。预警则值得是某些度量指标达到风险阈值时触发事件,进行告警通知提醒管理员介入。
- 2️⃣ 事件日志(Logging):日志的职责是记录离散事件,应用运行过程会持续输出日志数据,这些日志数据是业务系统运行状态的各种事件及业务处理逻辑时输出的,通过这些记录事后分析出程序的行为,基本上可以还原业务流程处理的全过程。事件日志可以详细解释系统的运行状态,但是存储和查询需要消耗大量的资源。
- 3️⃣ 链路追踪(Tracing):链路追踪大都是依据谷歌 Dapper 理论来实现的,调用链记录的是串联单个事务内全过程的日志数据,通过对请求打标、透传、串联,最终可以还原出一次完整的请求,可以帮助工程师轻松分析出请求中异常点。但是链路追踪和事件日志一样有着相同的问题就是资源消耗较大,通常也需要通过采样的方式减少数据量。
3.2 可观测性的产品体系
CNCF 云原生生态也整合了可观测性体系,将可观测性的能力作为云原生底层基础设施能力 💪,从根本上解决了平台与业务运维工具杂乱,能力层次不齐的问题。如下图所示,CNCF 生态全景图中可观测性主要是按照 Monitoring 监控指标、Logging 事件日志 、Tracing 链路追踪三个维度来分类。
1️⃣ 监控指标(Monitoring):云原生监控指标可观测产品大都是从传统的监控产品发展而来的,传统监控中 Zabbix 以其高可用和图形化展示而广受欢迎。而在云原生时代,CNCF 孵化的监控工具 Prometheus 取代了以 Zabbix 为代表的众多传统监控工具,已基本成为云原生监控体系通用的解决方案,并可以通过配合 Grafana 工具实现监控数据图形化进行可视化分析。
2️⃣ 事件日志(Logging):在业界中,事件日志可观测产品也已经是一片红海。日志管理方案大都包含日志收集、日志聚合、日志存储与分析几个模块,具体过程是日志收集工具与应用程序容器一起运行,并直接从应用程序收集消息,然后将消息转发到中央日志存储以进行汇总和分析。在这方面 Elastic Stack 日志解决方案独占鳌头,几乎覆盖了日志管理的全流程,其中一大变数是用于日志聚合、过滤等业务的 Logstash 效能较差,在未来可能会被 CNCF 孵化的 Fluentd 取代。
3️⃣ 链路追踪(Tracing):比起监控日志与事件日志,链路追踪可观测的产品竞争要相对激烈得多。其根本原因在于链路数据与实际业务和业务实现协议、编程语言等细粒度具体场景密切相关。这也导致针对不同产品实现和网络协议的链路追踪产品层出不穷,但是他们在功能实现上并没有太本质的差距,却又受制于实现细节,彼此互斥,很难搭配工作。CNCF 为了统一这一乱象,推出了 OpenTracing,它是一套与平台无关、与厂商无关、与语言无关的追踪协议规范,意在让链路追踪可观测更加规范化。
下图是 CNCF 云原生生态列出的监控指标、事件日志、链路追踪领域的著名产品,图可能比较老了,最新 CNCF 云原生可观测产品生态可查看 CNCF Cloud Native Interactive Landscape(新图都有水印)。
04 监控指标可观测
4.1 监控指标处理流程
前面我们已经提到监控指标是指对系统中某一类信息的统计聚合,用于观察系统的状态和趋势 📈 。离我们最近的系统状态监控指标可能就是面前电脑的任务管理器了,Windows 系统你可以按 CTRL
+ALT
+DEL
呼出任务管理器,我在 Ubuntu 中使用 top
命令也能看到相似的页面如下图所示 📊。
大多监控指标可观测产品都是基于这种指标数据实现的,他们将监控对象的指标收集并存储为时间序列数据 🕜,即指标信息与记录时的时间戳以及称为标签的可选键值对一起存储,然后基于这些数据进行分析和告警 📣。
我们以 Prometheus 为例来介绍监控指标的处理流程。
Prometheus 形成的监控指标可观测解决方案并不是由其一力完成的,他依靠的是他的生态系统,下图说明了 Prometheus 的架构及其一些生态系统组件:
主要组件简介如下:
Prometheus 服务器(Prometheus Server)
:用于收集和存储监控指标数据客户端库(Client Libraries)
:用于检测应用程序代码导出器(Exporters)
:将监控数据采集的端点通过 HTTP 服务等形式暴露给 Prometheus Server推送网关(PushGateway)
:当网络环境不允许 Prometheus Server 和 Exporter 进行通信时,可以使用 PushGateway 来进行中转,处理短期工作。告警管理器(AlertManager)
:创建告警规则,处理告警任务
下面我们结合 Prometheus 的组件具体介绍监控指标的处理流程。
4.2 数据收集
监控指标数据收集需要要解决两个问题:1️⃣ 如何定义指标? 2️⃣ 如何将这些指标告诉服务端?
4.2.1 如何定义指标 ❓
Prometheus 客户端库(Client Libraries)提供四种核心指标类型 📑。这些目前仅在客户端库(以启用针对特定类型的使用量身定制的 API)和有线协议中进行区分,Prometheus 服务器尚未使用类型信息,并将所有数据扁平化为无类型时间序列。
- 计数度量器(Counter):计数器是一个累积度量,它代表一个单调递增的计数器;可以使用计数器来表示服务的请求数、完成的任务数或错误数等合计量。
- 瞬态度量器(Gauge):瞬态度量器比计数器更简单,它就表示某个指标在某个时点可以任意上下的单个数值;瞬态度量通常用于测量值,例如温度或当前内存使用情况等,但也用于可以上下波动的计数,如并发请求的数量。
- 直方图度量器(Histogram):直方图是常见的二维统计图,它的两个坐标分别是统计样本和该样本对应的某个属性的度量,以长条图的形式表示具体数值。直方图通常是对观察结果进行采样,例如请求持续时间或响应大小等,并将它们计入可配置的存储桶中,同时还提供所有观察值的总和。
- 采样点分位图度量器(Summary):分位图是统计学中通过比较各分位数的分布情况的工具,用于验证实际值与理论值的差距,评估理论值与实际值之间的拟合度。分位图通常也是对观察结果进行采样例如请求持续时间和响应大小等,它不仅提供了观察总数和所有观察值的总和,同时也计算了滑动时间窗口上的可配置分位数。
4.2.2 如何将这些指标告诉服务端 ❓
监控系统获取
目标应用的指标通常有两种方式:
- 拉取式采集(Pull-Based Metrics Collection):监控系统主动从目标应用中拉取指标
- 推送式采集(Push-Based Metrics Collection):由目标系统主动向监控系统推送指标
Prometheus 结合了两种收集指标数据的方式,他基于 Pull 架构的同时还能够有限度地兼容 Push 式采集。⭕️ 一般情况下
⭕️ Prometheus 都是采用 Pull 进行采集,因为这种方式更加利于开发迭代、能够更容易地判断采集目标是否正常,同时可以手动调整采集目标。
Prometheus 的 Pull 采集方式主要是通过 Exporter 实现的,Exporter将监控数据采集的端点通过 HTTP 服务的形式暴露给 Prometheus Server,使其能够通过访问对应 Exporter 提供的 Endpoint 端点,即可以获取到需要采集的监控指标数据。
但是在一些❗️特殊情况下
❗️,Prometheus 也采用 Push 的采集方式,这也是推送网关(Push Gateway) 存在的意义。Push Gateway 是一个位于 Prometheus Server 外部的相对独立的中间模块,用于暂存将外部推送来的指标,然后再等候 Prometheus Server 从 Push Gateway 中去拉取。
而会使用到 Push Gateway 是为了解决 Pull 的一些固有缺陷 ❌,当网络环境不允许 Prometheus Server 和 Exporter 直接进行通信的情况下,例如目标应用位于内网,通过 NAT 访问外网,外网的 Prometheus 就无法主动连接目标系统,这时就需要目标应用主动推送指标数据。
4.3 存储查询
监控指标数据被采集过来之后,需要对齐进行存储,以便被下游业务的使用 🚿。但是,如果用传统关系数据库的存储监控指标数据,效果可能不会太理想。因为监控指标数据来源和类型众多,如果按照传统关系数据库需要建立关联关系错综、结构复杂的数据库模型,将带来极大的系统负担。
为了解决这种问题,🎈 时序数据库 🎈被提出,他是专门用于存储跟随时间而变化的数据,并且以时间(时间点或者时间区间)来建立索引的数据库,具有数据结构简单,数据量大的特点。
Prometheus 服务端自己就内置了一个强大时序数据库实现,该时序数据库提供了名为 PromQL
的数据查询语言,能对时序数据进行丰富的查询、聚合以及逻辑运算。
通过 PromQL 可以轻易实现指标之间的运算、聚合、统计等操作,在查询界面中往往需要通过 PromQL 计算多种指标的统计结果才能满足监控的需要。更多关于PromQL
的内容可以参考官方文档。
4.4 监控预警
采集存储监控指标数据的最终目的是要做系统运行状态分析和预警 📣。
Prometheus 中自带了一个界面解决方案 Console Template,用户可以使用该功能编写脚实现可用的监控功能。不过这种不够友好的交互方式,往往影响其良好使用,所以在生产环境下,Prometheus 是大多配合 Grafana 来进行可视化分析的。Grafana 提供的良好的可视化能力 📊,利于高效地进行系统长期趋势分析、对照分析、故障分析等分析工作。
除了为分析、决策、故障定位等提供支持的用户界面外,监控指标数据的另一种主要使用场景就是用来做预警 ⏰。Prometheus 提供了专门用于预警的 Alert Manager,将 Alert Manager 与 Prometheus 关联后,可以设置某个指标在多长时间内达到何种条件就会触发预警状态,触发预警后,可根据路由中配置的接收器来通知用户。
05 事件日志可观测
5.1 事件日志处理流程
日志的职责是记录离散事件,通过这些记录事后分析出程序的行为 💃🏃,譬如曾经调用过什么方法,曾经操作过哪些数据,等等。打印日志被认为是程序中最简单的工作之一,它无可或缺却不太被重视 😴,调试问题时它常常是分析问题的关键。下面展示的是 Nginx 服务器 Access Log 的日志数据:
211.94.114.14 - - [21/Nov/2017:10:44:52 +0800] "GET /scripts/search.jsp?q=%"<script>alert(1332010391)</script> HTTP/1.1" 200 51579
219.231.23.121 - - [21/Nov/2017:10:44:52 +0800] "GET /_upload/article/images/62/ca/3a0560164b04adb9823fc62e661d/9033ded0-c486-42c8-b774-8cd91b51f68b.jpg HTTP/1.1" 200 23131
219.231.23.121 - - [21/Nov/2017:10:44:52 +0800] "GET /_upload/article/images/62/ca/3a0560164b04adb9823fc62e661d/f9d59c1b-68ef-4460-8225-8f3dbbfd5a9a.jpg HTTP/1.1" 200 42453
219.231.23.121 - - [21/Nov/2017:10:44:52 +0800] "GET /scripts/search.jsp?q=%"<script>alert(1332010391)</script> HTTP/1.1" 200 38918
211.94.114.14 - - [21/Nov/2017:10:44:52 +0800] "GET /scripts/search.jsp?q=%"<script>alert(1332010391)</script> HTTP/1.1" 200 65814
219.231.23.121 - - [21/Nov/2017:10:44:52 +0800] "GET /scripts/search.jsp?q=%"<script>alert(1332010391)</script> HTTP/1.1" 200 41498
输出日志的确很容易,但 💢 收集和分析日志却可能会很复杂 💢,尤其随着云原生和微服务技术的迅猛发展,系统结构日益复杂。面对成千上万的节点,面对迅速滚动的事件信息,面对 TB 级别的日志数据,传输与收集都并不简单,分析日志数据并从中挖掘出有价值的信息更是难上加难。
这时候专业的事件日志可观测产品就可以大显神通了 👼,他们提供专门的全局查询和可视化功能让日志管理更加便捷,让获取有价值的日志信息更加容易。
我们以最成熟的 Elastic Stack 技术栈为例,介绍该事件日志的处理流程中的每个步骤。下图展示的是 Elastic Stack 一般架构体系,当然其中的 Kafka 并不是 Elastic Stack 的一员,但是它可以优化 ELK 日志处理架构,更多了解可以参考笔者之前的文章 使用 Kafka 缓存优化 ELK 日志收集 欢迎 一键三连
👍 💬 ⭐️。
从左到右 ELK 架构的各组件介绍如下:
- 日志收集 Filebeat:Filebeat 作为日志搜集器可以在节点上监听目标应用的日志文件进行日志采集。相比直接使用 Logstash 进行日志采集,Filebeat 所占系统的 CPU 和内存等系统资源开销要小很多。
- 聚合加工 Logstash:Logstash 是一个具有实时渠道能力的数据收集引擎,主要用于日志的收集与解析,并将其存入 ElasticSearch 中。
- 存储查询 ElasticSearch:Elasticsearch 是一个建立在全文搜索引擎 Apache Lucene 基础上的搜索引擎,能够实现实时的分布式搜索和分析引擎,也可以用于全文搜索,结构化搜索以及分析。
- 可视化分析 Kibana:Kibana 为 Elasticsearch 提供分析和可视化的 Web 平台。它可以在 Elasticsearch 的索引中查找,交互数据,并生成各种维度的表图。
事件日志可观测总体上也可分为数据收集、聚合加工和存储查询三个过程,Elastic Stack 中每个过程在框架中设置了如上所述的对应组件来实现,下面我们结合 Elastic Stack 的组件具体每个过程中的实现方法。
5.2 数据收集
5.2.1 采集原理 😯
早期 ELK 框架中日志收集的任务是由 Logstash 来承担的,它还可以独立部署节点进行日志收集。但是由于其运行过程中需要消耗大量系统资源
❌,所以不适用于大规模多节点的部署场景。为此 Elastic 公司专门使用 Golang 重写了一个功能较少,却更轻量高效的日志收集器 Filebeat ⭕️。
Filebeat是用于转发和集中日志数据的轻量级传送程序。作为服务器上的代理安装,Filebeat 作为服务器代理可以监视指定的日志文件或位置,收集事件日志,并将它们转发到 Logstash 和 ElasticSearch 进行加工和存储。
Filebeat 进行日志数据采集的原理如下图所示:Filebeat 通过输入 Input
在指定的位置中查找日志数据;然后在找到的每个日志文件中启动采集器 Harvester
;每个采集器读取单个日志文件中的新日志数据,并将这些日志数据发送到处理程序Spooler
,处理程序完成对日志数据的聚集和缓存,最后将这些数据发送到为 Filebeat 配置的输出中。更加底层的 Filebeat 采集原理可以参考这边博文 ➡️ 容器日志采集利器:Filebeat深度剖析与实践。
5.2.2 缓存优化 😉
如果直接将 Filebeat 在节点上采集日志数据传输给 LogStash 或 Elasticsearch 存储,会很容易出现性能瓶颈 🍺。在大型分布式系统中,每天的日志量是接近 PB
量级的,日志收集器的部署实例数也能达到百万量级,这种情况下用于聚集和存储的 LogStash 或 Elasticsearch 将不堪重负 🙀。
为此在 Filebeat 和它的输出对象之间加上一个缓存区,这样在面对突发流量时,Logstash 或 Elasticsearch 处理能力出现瓶颈时自动削峰填谷,甚至当它们短时间停顿,也不会丢失日志数据。这样就增强了日志数据聚集和存储步骤的抗压能力,保证了整体架构的可靠性和稳定性。
实现缓存的方法有很多,通常主要使用 Kafka 或者 Redis 作为缓冲层,笔者之前已经有过相关内容的详细介绍,这里就不再赘述,有兴趣可以通过一下链接进一步了解这些内容,欢迎 一键三连
👍 💬 ⭐️。
5.3 加工聚合
日志数据往往是非结构化的 😵,一行日志中通常会包含多项信息,如果不做处理,那在 Elasticsearch 就只能以全文检索的原始方式去使用日志,既不利于统计对比,也不利于条件过滤。所以在日志数据收集之后,存入 Elasticsearch 之前,还需要对其进行加工和聚合处理。
ELK 中 通常是使用 Logstash 完成这个任务,它可以把日志条目这种非结构化数据,通过 Grok
表达式语法 🔄 转换为结构化数据 。在进行结构化的过程中,还可以根据需要,调用其他插件来统一时间格式、类型转换、查询归类等额外处理工作。最后将被结构化的日志数据以 JSON 格式输出 🔠 到 Elasticsearch 中。下面展示了一条 Nginx 服务器的 Access Log
日志数据被结构化的情况:
14.123.255.234 - - [19/Feb/2020:00:12:11 +0800] "GET /index.html HTTP/1.1" 200 1314 "https://icyfenix.cn" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36"
数据项 | 值 |
---|---|
IP | 14.123.255.234 |
Username | null |
Datetime | 19/Feb/2020:00:12:11 +0800 |
Method | GET |
URL | /index.html |
Protocol | HTTP/1.1 |
Status | 200 |
Size | 1314 |
Refer | https://icyfenix.cn |
Agent | Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36 |
日志数据经过 Logstash 的结构化转换后,Elasticsearch 就可方便地针对不同数据项来建立索引,进行条件查询、统计、聚合等操作。
聚合日志的主要目的是便于分析,因为日志数据记录的往往是离散事件,我们很难通过这些离散的事件获取有价值的信息 💡,所以需要对这些离散数据进行聚合操作 🔍。根据某一特征或性质将离散的数据聚合,就可以从中获取离散日志的统计信息,实现价值信息挖掘。ELK 框架有两种方式实现聚合操作:
- Logstash 中聚合操作:在 Logstash 中通过聚合插件来完成在收集日志后自动生成某些常用的、固定的聚合指标。
- Elasticsearch 中聚合操作:通过 Elasticsearch 本身的处理能力做实时的聚合统计,可获取日志数据的实时统计信息。
5.4 存储查询
经过收集、缓冲、加工聚合的日志数据,最终将放入 Elasticsearch 中索引存储了 📬。Elasticsearch 是整个 Elastic Stack 技术栈的核心,因为 Elasticsearch 的优势正好与日志分析的需求完美契合 💑。
首先从数据特征
的角度看,日志是典型的基于时间的流数据 🚿,而且具有一次写入不再更改的特点。使用 Elasticsearch 存储日志数据并依据时间范围作为索引,例如按月、按周或者按日、按时。无论使用什么样的时间范围,因为日志是不间断的流数据,那么我们可以🔺 预先创建 🔻全部 Elasticsearch 索引,这就免去了动态创建的寻找节点、创建分片、在集群中广播变动信息等开销,具备更高的存储效能。
然后从数据价值
的角度看,日志基本上只会以最近的数据为检索目标,随着时间推移,早期的数据将逐渐失去价值。这点决定了可以很容易区分出冷数据 ❄️ 和热数据 🔥,进而对不同数据采用不一样的硬件策略,Elasticsearch 很容易实现这一机制。
最后从数据使用
的角度看,分析日志很依赖全文检索和即时查询,对实时性的要求是处于实时与离线两者之间的近实时,即不强求日志产生后立刻能查到,但也不能接受日志产生之后按小时甚至按天的频率来更新,这些检索能力和近实时性,也正好都是 Elasticsearch 的强项。
所以总的来说用 Elasticsearch 存储日志数据是天生绝配 💑
采集存储日志数据的最终目的是要分析日志。Elasticsearch 只提供了 API 层面的查询能力,在使用时一般配合 Kibana 一起使用,实现日志数据可视化分析。Kibana 尽管只负责图形界面和展示 📊,但它又不止于此,它可以把存储在 Elasticsearch 中的数据被检索、聚合、统计后,定制形成各种图形、表格、指标、统计,以此观察系统的运行状态,找出日志事件中潜藏的规律和隐患。Kibana 的官方展示效果图如下:
06 链路追踪可观测
6.1 追踪数据的概念
6.1.1 链路追踪初步理解 🙇
微服务架构被广泛应用与大规模的 Web 服务,策略独立的服务模块,使得服务更新和部署更加便利,但是各种各样微服务之间的复杂关系和巨大的微服务规模使得保证服务提供的可靠性更加困难 🗿。为了保证微服务架构的可靠性,需要准确高效的故障排除,而调用轨迹异常检测是该过程的重要环节。管理人员通过检测到的异常调用轨迹对故障根因进行分析和定位。
微服务架构的链路追踪需要记录在一次特定的请求后系统中完成的所有工作的信息。如下图所示展现的是一个和 5台服务器相关的一个服务,包括:前端(A),两个中间层(B和C),以及两个后端(D和E)。当一个用户发起一个请求时,首先到达前端,然后发送两个RPC到服务器B和C。B会马上做出反应,但是C需要和后端的D和E交互之后再返还给A,由A来响应最初的请求。对于这样一个请求,简单实用的分布式跟踪的实现,就是为服务器上每一次你发送和接收动作来收集跟踪标识符(message identifiers)和时间戳(timestamped events)。
6.1.2 认识追踪与跨度 🙆
现代分布式链路追踪公认的起源是 Google 在 2010 年发表的论文 📄《Dapper : a Large-Scale Distributed Systems Tracing Infrastructure》📄。
为了有效地进行分布式追踪,Dapper 提出了追踪(Trace)与跨度(Span)
两个概念:
- 追踪(Trace):从客户端发起请求抵达系统的边界开始,记录请求流经的每一个服务,直到到向客户端返回响应为止,这整个过程就称为一次追踪。
- 跨度(Span):由于每次 Trace 都可能会调用数量不定、坐标不定的多个服务,为了能够记录具体调用了哪些服务,以及调用的顺序、开始时点、执行时长等信息,每次开始调用服务前都要先埋入一个调用记录,这个记录称为一个跨度。
Dapper 使用以跨度为基本树节点的跟踪树构建跟踪模型,并为每个跨度记录了一个可读的 span name, span id, parent id
,这样就能重建出一次分布式跟踪过程中不同跨度之间的关系。没有 parent id
的跨度被称为根跨度
。一次特定跟踪的所有相关跨度会共享同一个通用的 trace id
。换句话说每一个追踪实际上都是由若干个有顺序、有层级关系的跨度所组成一颗追踪树(Trace Tree),如下图所示:
利用追踪(Trace)与跨度(Span)可以构建一副巨大的系统服务调用拓扑图 🏇。根据拓扑图中跨度记录的时间信息和响应结果就可以定位到缓慢或者出错的服务;将追踪与历史记录进行对比统计,就可以从系统整体层面分析服务性能,定位性能优化的目标。这就是现代分布式链路追踪的基础原理。
6.2 基于日志的追踪数据收集
前面我们已经提到过比起监控日志与事件日志,链路数据与实际业务和业务实现协议、编程语言等细粒度具体场景密切相关,导致了链路追踪产品的多样性 🏃💃,但是他们在实现原理上大都来源于 Dapper
👵 👴。
所以,在本节我们不以某个具有代表性的链路追踪产品来介绍其实现原理与基础原理,而是以 Dapper 为依据介绍链路追踪产品实现的基础理论。而链路追踪实现的难点在于追踪数据的采集,一般追踪数据的采集有 1️⃣ 基于日志和 2️⃣ 基于服务两种方式,我们先介绍基于日志数据实现链路追踪的方式。
基于日志的追踪的思路是将 Trace、Span 等信息直接输出到应用日志中,然后根据收集到的日志数据,从全局日志信息中反推出完整的调用链拓扑关系。
基于日志的追踪数据收集的 优点
😍 在于其对网络消息完全没有侵入性,对应用程序只有很少量的侵入性,对性能影响也非常低。但其 缺点
😡 是直接依赖于日志归集过程,日志本身不追求绝对的连续与一致,这也使得基于日志的追踪往往不如其他两种追踪实现来的精准。另外,业务服务的调用与日志的归集并不是同时完成的,也通常不由同一个进程完成,有可能发生业务调用已经顺利结束了,但由于日志归集不及时或者精度丢失,导致日志出现延迟或缺失记录,进而产生追踪失真。
Dapper 的跟踪记录和收集管道实现如下图所示,共分为三个阶段:
- 首先,把
span
数据写入到本地日志文件 - 然后 Dapper 守护进程从所有生产主机中将他们拉取出来
- 最终写入到 Dapper 的
Bigtable
仓库中,其中Bigtable
中的行表示一次跟踪,列表示一个span
。
6.3 基于服务的追踪数据收集
基于服务追踪的实现思路是通过某些手段给目标应用注入追踪探针(Probe),通过探针获取服务调用信息并发送给链路追踪系统。
探针
在结构上可视为一个寄生在目标服务身上的小型微服务系统,它一般会有自己专用的服务注册、心跳检测等功能,有专门的数据收集协议,把从目标系统中监控得到的服务调用信息,通过另一次独立的 HTTP 或者 RPC 请求发送给追踪系统。
因此,基于服务的链路追踪实现的 缺点
😡 在于比基于日志的追踪消耗更多的资源,也有更强的侵入性。但是反之其 优点
😍 就是这些资源消耗换来的收益是追踪的精确性与稳定性都有所保证,不必再依靠日志归集来传输追踪数据。
基于服务的追踪是目前较为常见的追踪实现方式,被 Zipkin、SkyWalking、Pinpoint 等主流追踪系统广泛采用。下面展示的是 Pinpoint 的追踪效果截图,从图中可以看到参数、变量等相当详细方法级调用信息。
07 总结
总的来说,云原生可观测性方兴未艾 📈,自不必多说其对应云原生的重要性 🔥,因为云原生的应用系统趋于规模化和复杂化,越是复杂的庞大机器越是会强调其可靠性和稳定性。
在来总结一下本文的内容 🙋:🌱 首先我们介绍了云原生的概念,接着引出了可观测性对于云原生的重要意义,并将其与传统监控进行了对比突出可观测性的新内涵。🌹 然后,我们分别介绍了实现可观测性的三大数据监控指标、事件日志和链路追踪,以及基于不同数据的可观测产品代表。🌳 最后,我们基于这些可观测产品代表介绍了他们实现可观测的原理,分别是:基于 Prometheus 生态的监控指标可观测实现方案;基于 ELK 日志管理的事件日志可观测实现方案;基于 Dapper 理论的链路追踪可观测实现方案。
产品上,监控指标领域大有被 Prometheus 一统江湖的趋势,事件日志领域 ELK 已经有着不可撼动的地位,而反观链路追踪领域则是百花齐放缺乏统一规则,但是都是从 Dapper 发展而来同根同祖。
云原生可观测未来需要一个大一统的可落地产品,通过统一的标准汇聚三者的数据,挖掘交叉区域的价值。而 CNCF 推出的 OpenTelemetry 可以说是云原生可观测性体系的一个希望,他提供了统一的协议及标准,这可以有效整合云原生可观测产品体系,实现合力。
OpenTelemetry 未来有着无限可能,笔者也正在努力学习相关内容,后期会进一步具体介绍这个未来之星 OpenTelemetry 。
参考资料
Dapper, a Large-Scale Distributed Systems Tracing Infrastructure
如果文章对你有帮助,别忘了一键三连呀 👍 💬 ⭐️ 。你的支持是我坚持的最大动力 🔥🔥🔥 。
- 点赞
- 收藏
- 关注作者
评论(0)