Grafana-可观测性指南-全-
Grafana 可观测性指南(全)
原文:
annas-archive.org/md5/78e3e192dcfb3991c243c49c506b56e3译者:飞龙
前言
你好,欢迎!Grafana 的可观察性是一本关于 Grafana Labs 提供的可观察性和监控工具的书。Grafana Labs 是业界领先的开源工具提供商,致力于收集、存储和可视化来自 IT 系统的数据。本书主要面向将与这些系统交互的 IT 工程师,无论他们从事哪个领域的工作。
我们写这本书是因为我们在各个组织中看到了很多常见的问题:
-
设计时没有考虑扩展策略的系统,正在面临额外的数据负载或团队使用该系统的压力
-
组织中未能正确归因运营成本,导致成本分析和管理不善
-
事件管理流程将参与其中的人视作没有睡眠周期或副交感神经系统的机器人
在本书中,我们将使用 OpenTelemetry 演示应用程序来模拟真实世界的环境,并将收集到的数据发送到我们将创建的免费的 Grafana Cloud 账户。这将引导你通过 Grafana 工具来收集遥测数据,同时也让你亲身体验使用 Grafana 提供的管理和支持工具。这种方法将教你如何以一种让任何人都可以独立尝试和学习的方式运行 Grafana 工具。
这是 Grafana 的一个激动人心的时刻,它被认定为2023 年 Gartner 可观察性魔力象限中的远见者(www.gartner.com/en/documents/4500499)。他们最近在两个趋势领域做出了变革:
-
成本降低:这使得 Grafana 成为可观察性领域首个推出工具的供应商,这些工具不仅帮助你理解成本,还能降低成本。
-
人工智能(AI):Grafana 推出了生成性 AI 工具,帮助日常操作以简单而有效的方式进行,例如自动撰写事件总结。Grafana Labs 最近还收购了Asserts.ai,以简化根本原因分析并加速问题检测。
我们希望你喜欢和我们一起学习一些新东西,并且在过程中获得乐趣!
本书适合的人群
IT 工程师、支持团队和领导者可以获得关于如何将可观察性平台的巨大功能引入到他们组织的实际见解。本书将重点介绍以下领域的工程师:
-
软件开发:学习如何快速对应用程序进行仪器化并生成出色的可视化,使得应用程序能够轻松支持
-
运维团队(DevOps、运维、网站可靠性、平台或基础设施):学习如何管理可观察性平台或其他关键基础设施平台,并像管理任何其他应用程序一样管理这些平台
-
支持团队:学习如何与开发和运维团队密切合作,建立良好的可视化和警报机制,以便快速响应客户需求和 IT 事件
本书还将明确阐述领导力在事件管理、成本管理以及为这个强大数据集建立准确数据模型中的作用。
本书涵盖的内容
第一章,介绍可观测性和 Grafana 堆栈,介绍了 Grafana 产品堆栈与整体可观测性之间的关系。您将了解目标受众以及这如何影响您的设计。我们将查看可观测性工具的路线图,并比较 Grafana 与其他解决方案的优劣。我们还将探讨架构部署模型,从自托管到云端解决方案。最终,您将获得关于“为什么选择 Grafana?”的答案。
第二章,对应用程序和基础设施进行监控,从高层次介绍了每种遥测类型的常见协议和最佳实践。您将了解多个编程语言中广泛使用的库,这些库使得对应用程序的监控变得简单。还将讨论从基础设施组件收集数据的常见协议和策略。本章提供了技术领域的高层次概述,旨在成为快速参考的重要资料。
第三章,使用演示应用程序设置学习环境,解释了如何安装和设置一个支持后续章节学习的环境。您还将学习如何探索演示应用程序产生的遥测数据,并为自己的服务添加监控。
第四章,使用 Loki 查看日志,带您通过工作示例理解 LogQL。然后,您将了解常见的日志格式及其优缺点。最后,您将了解 Loki 的重要架构设计,并掌握与其合作时的最佳实践。
第五章,使用 Grafana Mimir 和 Prometheus 进行度量监控,讨论了通过真实数据理解 PromQL 的工作示例。将讨论有关不同度量协议的详细信息。最后,您将了解支持 Mimir、Prometheus 和 Graphite 的重要架构设计,并掌握与这些工具合作时的最佳实践。
第六章,使用 Grafana Tempo 跟踪技术细节,展示了使用真实数据理解 TraceQL 的工作示例。将讨论有关不同追踪协议的详细信息。最后,您将了解 Tempo 的重要架构设计,并掌握与其合作时的最佳实践。
第七章,使用 Kubernetes、AWS、GCP 和 Azure 查询基础设施,描述了用于捕获基础设施遥测的设置和配置。你将了解 Kubernetes 的不同选项。此外,你还将研究允许 Grafana 从云供应商(如 AWS、GCP 和 Azure)查询数据的主要插件。你将了解如何处理大量遥测数据,尤其是在直接连接无法扩展的情况下。本章还将介绍如何在数据进入 Grafana 之前进行遥测数据的过滤和选择,以优化安全性和成本。
第八章,使用仪表盘显示数据,解释了如何在 Grafana UI 中设置你的第一个仪表盘。你还将学习如何以有效且有意义的方式展示你的遥测数据。本章还将教你如何管理 Grafana 仪表盘,以确保其有条理且安全。
第九章,使用警报管理事件,描述了如何使用警报管理器设置你的第一个 Grafana 警报。你将学习如何设计一种警报策略,将关键业务警报优先于普通通知。此外,你还将了解警报通知策略、不同的传递方式以及需要注意的事项。
第十章,使用基础设施即代码进行自动化,为你提供了自动化 Grafana 堆栈部署某些部分的工具和方法,同时引入标准和质量检查。你将深入了解 Grafana API,学习如何与 Terraform 配合使用,并了解如何通过验证保护变更。
第十一章,构建可观测性平台架构,将向你展示那些负责提供高效且易于使用的可观测性平台的人员,如何构建平台结构,以便能让你的内部客户满意。在我们所处的环境中,快速高效地提供这些平台服务至关重要,这样才能将更多的时间投入到客户面向的产品生产中。本章旨在基于已有的知识,帮助你快速启动并运行。
第十二章,使用 Grafana 进行真实用户监控,向你介绍前端应用程序的可观测性,使用 Grafana Faro 和 Grafana Cloud Frontend Observability 进行真实用户监控(RUM)。本章将讨论如何对前端浏览器应用程序进行监控。你将学习如何捕获前端遥测数据,并将其与后端遥测数据关联,以实现全栈可观测性。
第十三章,通过 Grafana Pyroscope 和 k6 进行应用性能监控,介绍了如何使用 Grafana Pyroscope 和 k6 进行应用性能分析和性能剖析。你将获得一个高层次的概览,讨论 k6 在烟雾测试、突发测试、压力测试和浸泡测试中的各个方面,以及如何使用 Pyroscope 在生产环境和测试环境中持续分析应用程序。
第十四章,通过可观察性支持 DevOps 流程,带领你了解 DevOps 流程以及如何利用 Grafana 通过可观察性提升这些流程。你将学习如何在开发阶段使用 Grafana 堆栈加速工程师的反馈循环。你将理解如何为工程师准备好在生产环境中操作产品。最后,你将学习何时以及如何实施 CLI 和自动化工具以增强开发工作流。
第十五章,通过 Grafana 进行故障排除、实施最佳实践及更多内容,通过讲解在生产环境中使用 Grafana 的最佳实践来结束本书。你还将学习一些有价值的故障排除技巧,以帮助你应对日常运营中的高流量系统。你还将了解与安全性和商业智能相关的遥测数据的其他注意事项。
充分利用本书
下表展示了本书中将使用的软件的操作系统要求:
| 本书涵盖的软件/硬件 | 操作系统要求 |
|---|---|
| Kubernetes v1.26 | 支持 Windows、macOS 或 Linux,配备双核 CPU 和 4GB 内存 |
| Docker v23 | 支持 Windows、macOS 或 Linux,配备双核 CPU 和 4GB 内存 |
如果你使用的是本书的数字版本,我们建议你自己输入代码或通过本书的 GitHub 仓库获取代码(下一节将提供链接)。这样做将帮助你避免与复制和粘贴代码相关的潜在错误。
下载示例代码文件
你可以从 GitHub 下载本书的示例代码文件,链接地址为 github.com/PacktPublishing/Observability-with-Grafana。如果代码有更新,它将在 GitHub 仓库中更新。
我们还提供了来自我们丰富的书籍和视频目录中的其他代码包,链接地址为 github.com/PacktPublishing/。欢迎查看!
行动中的代码
本书的《行动中的代码》视频可以在 packt.link/v59Jp 上观看。
使用的约定
本书中使用了多种文本约定。
文本中的代码:表示文本中的代码词汇、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 用户名。举个例子:“用于获取此信息的函数是 rate() 函数。”
一段代码设置如下:
histogram_quantile(
0.95, sum(
rate(
http_server_duration_milliseconds_bucket{}[$__rate_interval])
) by (le)
)
任何命令行输入或输出如下所示:
$ helm upgrade owg open-telemetry/opentelemetry-collector -f OTEL-Collector.yaml
粗体:表示新术语、重要词汇,或您在屏幕上看到的词汇。例如,在菜单或对话框中的词汇通常显示为粗体。举个例子:“在仪表板的设置屏幕上,您可以添加或删除单个仪表板的标签。”
提示或重要说明
显示如下。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果您对本书的任何部分有疑问,请通过电子邮件联系我们 customercare@packtpub.com,并在邮件主题中注明书名。
勘误:虽然我们已经尽一切努力确保内容的准确性,但错误难免发生。如果您在本书中发现错误,我们非常感激您能向我们报告。请访问 www.packtpub.com/support/errata 并填写表单。
盗版:如果您在互联网上发现我们作品的任何非法复制形式,我们将非常感激您提供该位置或网站名称。请通过 copyright@packt.com 联系我们,并附上材料的链接。
如果您有兴趣成为作者:如果您在某个领域有专长,并且有兴趣撰写或为书籍做贡献,请访问 authors.packtpub.com。
分享您的想法
一旦您阅读了《Grafana 可观察性》,我们很想听听您的想法!请点击这里直接前往本书的亚马逊评论页面并分享您的反馈。
您的反馈对我们以及技术社区非常重要,能帮助我们确保提供优质的内容。
下载本书的免费 PDF 副本
感谢购买本书!
您喜欢随时随地阅读,但无法随身携带纸质书籍吗?
您的电子书购买无法与您选择的设备兼容吗?
不用担心,现在每本 Packt 书籍,您都可以免费获得该书的无 DRM PDF 版本。
在任何地方、任何设备上阅读。可以直接从您最喜欢的技术书籍中搜索、复制和粘贴代码到您的应用程序中。
福利还不止这些,您还可以获得独家折扣、时事通讯以及每日送达的精彩免费内容。
请按照以下简单步骤享受这些福利:
- 扫描二维码或访问下面的链接

packt.link/free-ebook/9781803248004
-
提交您的购买证明
-
就这些!我们会直接将免费的 PDF 文件和其他福利发送到您的邮箱
第一部分:开始使用 Grafana 和可观测性
本书的这一部分将介绍 Grafana 和可观测性。你将了解遥测数据的生产者和消费者。你将探讨如何为应用程序和基础设施添加监控工具。接着,你将设置一个学习环境,并在接下来的章节中逐步增强,以提供使用 Grafana 实现可观测性的全面示例。
本部分包含以下章节:
-
第一章**, 介绍可观测性和 Grafana 堆栈
-
第二章**, 为应用程序和基础设施添加监控工具
-
第三章**, 使用演示应用程序设置学习环境
第一章:介绍观察性与 Grafana 技术栈
我们当前使用的现代计算机系统已经从“复杂”领域转向“复杂性”领域,在这些系统中,相互作用的变量数目使其最终变得无法预测和无法控制。我们使用“复杂”和“复杂性”这两个术语是根据系统理论的定义。一个复杂的系统,如引擎,具有组件之间明确的因果关系。而一个复杂系统,如城市交通的流动,则通过组件之间的相互作用展现出涌现行为。
根据 Ponemon Institute 2016 年的估算,每分钟停机的平均成本为 9000 美元,若组织未采取措施管理这一风险,复杂性可能会导致重大的财务损失。观察性提供了一种减轻这些风险的方式,但如果实施不当或没有明确的商业目标,使系统具备观察性也会带来财务风险。
本书将帮助你深入理解观察性是什么,以及可能使用它的客户是谁。我们将探索如何使用来自 Grafana Labs 的工具来获取组织的可见性。这些工具包括 Loki、Prometheus、Mimir、Tempo、Frontend Observability、Pyroscope 和 k6。你将学习如何使用服务水平指标(SLIs)和服务水平目标(SLOs)来获得清晰透明的信号,判断服务是否正常运行,并学习如何使用 Grafana 的事件响应工具来处理事件。最后,你将了解如何使用自动化工具如 Ansible、Terraform 和 Helm 来管理观察性平台。
本章旨在通过计算机领域之外的例子向所有受众介绍观察性。我们将介绍观察性工具使用的遥测类型,这将为你提供如何利用这些工具快速了解服务状态的概览。我们还将概述可能使用观察性系统的各种角色,这样你在后续的学习中可以在明确受益者的基础上探讨更复杂的概念。最后,我们将研究 Grafana 的Loki、Grafana、Tempo、Mimir(LGTM)技术栈,如何部署它,以及有哪些替代方案。
本章我们将涵盖以下主要内容:
-
观察性概述
-
遥测类型与技术
-
理解观察性的客户群
-
介绍 Grafana 技术栈
-
Grafana 技术栈的替代方案
-
部署 Grafana 技术栈
观察性概述
观察性这个术语借鉴自控制理论。在 IT 系统中,监控和观察性通常可以互换使用,因为这两个概念密切相关。监控是当系统出现问题时发出警报的能力,而观察性则是理解系统并确定是否存在问题及其原因的能力。
控制理论在 19 世纪末就蒸汽机中的离心调速器进行了形式化。此图显示了该系统的简化视图:

图 1.1 – 詹姆斯·瓦特的蒸汽机飞重调速器(来源:www.mpoweruk.com)
蒸汽机使用锅炉将水加热至压力容器中的蒸汽。蒸汽推动活塞前后运动,从而将热能转化为往复能量。在使用离心调速器的蒸汽机中,这种往复能量通过连接到活塞的轮子转化为旋转能量。离心调速器通过物理链接将系统向后连接到节气门。这意味着旋转速度控制节气门,而节气门又控制旋转速度。从物理上讲,这是通过调速器上的小球向外飞出并下落向内直到系统达到平衡来观察的。
监控定义了事先感兴趣的指标或事件。例如,调速器测量预定义的驱动轴转数。然后,节气门的可控性通过枢轴和执行杆组件提供。假设执行杆正确调整,调速器应控制节气门从完全打开到完全关闭。
相反,可观察性通过允许从系统的外部输出推断出其内部状态来实现。如果操作点调整设置不正确,调速器可能转得太快或太慢,从而使节气门控制失效。调速器转得过快或过慢也可能表明滑环卡住了,需要加油。重要的是,这些洞察可以在没有预先定义“过快”或“过慢”的情况下获得。得出调速器转速过快或过慢的结论,几乎不需要了解整个蒸汽机的详细信息。
从根本上讲,监控和可观察性都用于提高所讨论系统的可靠性和性能。
现在我们已经介绍了高层次的概念,接下来让我们探讨一个来自软件服务领域之外的实际例子。
案例研究 – 一艘船通过巴拿马运河
让我们想象一艘船通过巴拿马运河的阿瓜克拉水闸。这个过程可以通过以下图示来说明:

图 1.2 – 巴拿马运河的阿瓜克拉水闸
这些水闸中有一些方面我们可能需要监控:
-
每个闸门成功打开和关闭
-
每个水闸内的水位
-
一艘船通过水闸所需的时间
监控这些方面可能会突出我们需要注意的情况:
-
由于机械故障,闸门卡住无法关闭
-
由于泄漏,水位迅速下降
-
一艘船因卡住而需要花费更多时间才能通过闸门:
可能会出现这种情况:我们监控的数据处于可接受的范围内,但我们仍然可以观察到与正常情况的偏差,这应该促使进一步的行动:
-
锁墙顶部附近出现了一个小漏水点:
-
我们会看到水位下降,但只有当水位高于漏点时才会发生。
-
这可能会促使对锁墙进行维护工作。
-
-
一扇锁门打开得更慢,因为它需要维护:
-
我们会看到开关门之间的时间延长。
-
这可能会促使对锁门进行维护。
-
-
当风从某个特定方向吹来时,船只通过闸门的时间会更长:
-
我们可以比较每小时的平均通行速率。
-
这可能促使减少来自某个方向风力影响的工作。
-
现在我们已经看到了一个测量现实世界系统的例子,我们可以将这些类型的测量分为不同的数据类型,以便最适合应用。现在让我们介绍这些数据类型。
遥测类型和技术
可观测工具中无聊但重要的一部分是遥测——捕获有用数据,跨地点传输数据,并生成为组织提供价值的可视化、警报和报告。
用于构建监控和可观测系统的三种主要遥测类型是——指标、日志和分布式追踪。其他遥测类型可能会被一些供应商和在特定情况下使用。我们将在这里简要介绍这些内容,但它们将在本书的第十二章和第十三章中更详细地探讨。
指标
指标可以被视为在某一时刻记录的数值数据,并通过标签或维度加以丰富,以便进行分析。指标通常是频繁生成的,并且易于搜索,非常适合用来判断某些事情是否异常或不对劲。让我们来看一个显示时间变化的指标示例:

图 1.3 – 显示时间变化的指标
以巴拿马运河为例,我们可以将每个闸门的水位作为一个指标,在定期的时间间隔进行测量。为了有效使用这些数据,我们可能会添加一些标签:
-
锁名:阿瓜·克拉拉
-
锁室:下游闸室
-
运河:巴拿马运河
日志
日志被视为非结构化的字符串数据类型。它们在某一时刻被记录,通常包含大量关于正在发生的事情的信息。虽然日志可以是结构化的,但无法保证该结构会持续存在,因为日志的生产者掌握着日志结构的控制权。让我们来看一个例子:
Jun 26 2016 20:31:01 pc-ac-g1 gate-events no obstructions seen
Jun 26 2016 20:32:01 pc-ac-g1 gate-events starting motors
Jun 26 2016 20:32:30 pc-ac-g1 gate-events motors engaged successfully
Jun 26 2016 20:35:30 pc-ac-g1 gate-events stopping motors
Jun 26 2016 20:35:30 pc-ac-g1 gate-events gate open complete
在我们的例子中,开关锁门时的各种操作可以作为日志来表示。
几乎每个系统都会生成日志,而且它们通常提供非常详细的信息。这对于理解发生了什么非常有帮助。然而,数据量带来了两个问题:
-
搜索可能效率低下且缓慢。
-
由于数据是文本格式,知道应该搜索什么可能会很困难。例如,
error occurred、process failed和action did not complete successfully都可以用来描述故障,但没有共享的字符串可以用于搜索。
让我们看一个来自计算机系统的真实日志条目,看看日志数据通常是如何表示的:

图 1.4 – 显示时间上离散事件的日志
我们可以清楚地看到,系统已从日志条目中提取出多个字段。这些字段详细说明了日志条目的来源、发生时间以及其他各种信息。
分布式踪迹
分布式踪迹 显示了一个动作的端到端过程。它们从完成该动作的每一步骤中捕获信息。假设有一个涉及船只通过闸门系统的踪迹,我们将关注船只进出每个闸门的时间,并且希望能够比较不同的船只使用该系统的情况。整个过程可以赋予一个标识符,通常称为 trace ID。踪迹由多个 spans 组成。在我们的示例中,一个 span 将覆盖每个独立闸门的进出。这些 spans 会被赋予第二个标识符,称为 span ID。为了将这两者关联起来,每个踪迹中的 span 都会引用整个踪迹的 trace ID。以下截图展示了分布式踪迹如何在计算机应用中表示:

图 1.5 – 显示动作随时间关系的踪迹
现在我们已经引入了度量、日志和踪迹,让我们考虑一个更详细的示例,关于船只通过闸门的过程,以及在此过程中如何生成每种遥测类型:
-
船只进入第一道锁:
-
Span ID 创建完成
-
Trace ID 创建完成
-
上下文信息被添加到 Span 中,例如,船只标识
-
关键事件以时间戳形式记录在 Span 中,例如,闸门的开启和关闭
-
-
船只通过第一道锁:
-
Span 已关闭并提交给记录系统
-
第二道锁通知踪迹 ID 和 Span ID
-
-
船只通过第二道锁:
-
Span ID 创建完成
-
Trace ID 被添加到 Span 中
-
上下文信息被添加到 Span 中
-
在 Span 中记录关键事件及其时间戳
-
-
船只通过第二道锁:
-
Span 已关闭并提交给记录系统
-
第三道锁通知踪迹 ID 和 Span ID
-
-
船只通过第三道锁:
- 重复 步骤 3
-
船只通过第三道锁:
- Span 已关闭并提交给记录系统
现在让我们看一些其他的遥测类型。
其他遥测类型
指标、日志和追踪通常被称为三大支柱或黄金三角,是可观测性的核心组成部分。正如我们前面所概述的,可观测性是理解一个系统的能力。虽然指标、日志和追踪为我们提供了非常好的理解系统的能力,但它们并不是我们可能需要的唯一信号,这取决于我们需要在哪个抽象层次上观察系统。例如,当我们查看非常详细的层次时,可能会对应用程序在 CPU 和 RAM 层面的活动堆栈跟踪非常感兴趣。相反,如果我们关心的是 CI/CD 管道的执行,我们可能仅仅关心是否发生了部署,其他的就不再关注。
分析数据(堆栈跟踪)可以为我们提供系统使用资源(如 CPU 周期或内存)的非常详细的技术视图。由于云服务通常按小时收费,因此这种详细的分析可以轻松实现成本节约。
同样,事件可以从平台(如 CI/CD)中获取。这些事件可以提供大量的洞察,有助于缩短平均恢复时间(MTTR)。想象一下,当你在非工作时间响应警报时,发现服务的一个新版本刚在问题发生前就部署了。更棒的是,想象一下你不需要醒来,因为部署过程可以自动检查失败并回滚。事件与日志的区别仅在于事件代表了一个完整的动作。在我们之前在日志部分的例子中,我们创建了五条日志,但这些日志都指向同一事件(打开锁门)的不同阶段。作为一个相对通用的术语,事件有时会有其他含义。
现在我们已经介绍了技术的基本概念,接下来我们来谈谈将使用可观测性数据的客户。
介绍观察者的用户角色
可观测性涉及理解一个系统、识别系统是否存在问题以及理解问题的原因。那么,理解一个系统是什么意思呢?简单的回答是了解单个应用程序或 基础设施组件的状态。
在本节中,我们将介绍本书中将使用的用户角色。这些角色将帮助区分人们使用可观测性系统来回答的不同类型问题。
让我们快速看一下本书中将用作示例的用户角色及其角色:
| 名称 和角色 | 描述 | |
|---|---|---|
![]() |
Diego 开发者 | 前端、后端、全栈等 |
![]() |
Ophelia 操作员 | SRE、DevOps、DevSecOps、客户成功等 |
![]() |
Steven 服务 | 服务经理及其他任务 |
![]() |
Pelé产品 | 产品经理、产品负责人等 |
|
| Masha 经理 | 经理,高层领导等 |
表 1.1 – 用户角色介绍
现在,让我们更详细地了解这些用户。
Diego 开发人员

Diego 开发人员 工作在许多类型的系统上,从客户直接交互的前端应用程序,到让组织能够以令人满意的方式存储数据的后端系统。你甚至可能会发现他在为其他开发人员工作的平台上工作,这些平台帮助他们的应用程序安全、快速地集成、构建、交付和部署。
目标
他编写出色的软件,经过充分测试,且解决了客户的实际需求。
互动
当他不在编写代码时,他会与 Ophelia 操作员 一起处理出现的任何问题和疑问。
Pelé 产品 在他的团队中工作,提供客户需求的洞察。他们紧密合作,将这些需求转化为详细的计划,制定如何交付解决这些需求的软件。
Steven 服务 非常关注 Diego 所做的更改是否会影响客户的承诺。如果发生需要关注的事故,他也会是第一个叫醒 Diego 的人。提供给 Masha 经理 的数据帮助她了解成本分解。当 Diego 在开发平台上工作时,他还收集数据,帮助她获得来自业务的投资,用于那些表现不如预期的团队。
需求
Diego 真的需要一些易于使用的库来支持他编写的代码。他没有时间成为专家,他希望能够添加几行代码并迅速获得结果。
拥有明确的标准来衡量可接受的性能,使他能够轻松获得正确的结果。
痛点
当 Diego 的系统产生过多数据时,他发现很难从噪声中提取有用的信息。他也会因为上游决定更改工具而不得不修改代码,这让他感到沮丧。
Ophelia 操作员

Ophelia 操作员 工作在一个以运营为重点的环境中。你可能会看到她在客户服务角色中,或者作为开发团队的一员担任 DevOps 工程师。她可能是一个专注于组织系统可靠性的团队成员,或者她也可能在安全或金融领域工作,以确保业务安全平稳地运行。
目标
Ophelia 希望确保产品按预期运行。她也喜欢在没有被早晨的事故叫醒时,能保持安稳的工作。
互动
Ophelia 将与 Diego 开发人员 密切合作;有时是当她无法获得数据来理解问题时,需要提升客户的工单;有时是开发运行手册,以确保系统持续运行。有时,她还需要向 Diego 提供有关可接受性能指标的明确指导,以便她的团队能够确保系统对客户表现良好。
Steven Service 与 Ophelia 紧密合作。他们一起工作,确保事件尽量少发生,并且能够快速解决。Steven 确保跟踪业务数据中的变更和事件,并在事情不顺时调整流程。
Pelé Product 喜欢拥有显示其产品问题领域的数据。
需求
有效的工作需要良好的数据。能够看到客户遇到错误,可能决定了是立即解决问题,还是让客户等待几周才能得到回应。
在一次事故中,看到在问题开始时部署了新版本的服务,可以将一个持续数小时的事件转变为短暂的波动,从而让客户保持满意。
痛点
持续收到警报但无法解决根本问题是一个大问题。Ophelia 曾看到同事们因过度工作而精疲力尽,每当这种情况发生时,她也会想离开组织。
Steven Service

Steven Service 从事服务交付工作。他关心的是确保组织的服务能够顺利交付。在关键事件中介入并协调行动,确保尽快解决问题,是工作的一部分。同样,确保通过帮助他人以最安全的方式进行变更的流程也是他的责任。Steven 还与为组织运行提供关键服务的第三方供应商合作。
目标
他希望服务能够尽可能顺利运行,这样组织可以更多地专注于客户。
互动
Diego Developer 和 Ophelia Operator 经常与 Steven 创建的变更管理流程以及他管理的支持流程一起工作。在变更管理过程中,拥有准确的数据非常有帮助,可以确保流程尽可能顺畅。
Steven 与 Masha Manager 紧密合作,确保她能够访问展示哪些流程运作顺畅、哪些流程需要花时间改进的数据。
需求
他需要能够比较不同产品的交付情况,并将这些数据提供给 Masha 和业务部门。
在事故中,他需要尽可能快速地把合适的人找来开会,并且为事后分析保存记录。
痛点
在事故中,能够识别出合适的人来参加电话会议是他面临的常见问题。看到不同系统之间的对比,且谁能解决问题的问题一直争论不休,也让他非常担忧。
Pelé 产品

Pelé Product 在产品团队工作。你会看到他与客户一起工作,了解他们的需求,保持产品路线图有序,并将需求传达给开发人员,例如 Diego Developer,以便他们进行开发。你还可能看到他在理解并制定产品待办事项,以支持组织内开发人员使用的内部平台。
目标
Pelé 想要了解客户,给他们提供令人愉悦的产品,并让他们不断回归。
互动
他花了很多时间与Diego一起工作,他们可以查看相同的信息,真正理解客户在做什么,以及如何帮助他们做得更好。
Ophelia Operator 和 Steven Service 帮助 Pelé 保持产品的进度。如果发生了太多的事件,他们会要求大家重新集中精力确保稳定性。向客户提供大量特性却没有信任保障是没有意义的。
Pelé 与 Masha Manager 紧密合作,确保组织中拥有构建产品所需的合适技能团队。商业依赖她的领导力,确保这些开发人员拥有最佳的工具,帮助他们将代码推送到客户面前,使其能够使用。
需求
Pelé 需要能够理解客户的痛点,即使他们在用户研究中未能清楚表达这些问题。
他需要能够为自己和 Diego、Ophelia 提供共同语言的数据。有时候,他们可能会过于关注一些具体数字,例如减少请求的毫秒数,而实际上,改善一个糟糕的工作流程对客户体验的提升会更为显著。
痛点
Pelé 讨厌无法高层次地看到客户的行为。了解应用程序中最常使用的部分以及完全不被使用的部分,能让他知道应该在哪些方面集中时间和资源。
尽管客户从不直接告诉他他们需要稳定性,但如果缺乏这一点,他们会迅速失去信任,并开始寻找替代方案。
Masha 经理

Masha 从事管理工作。你可能会看到她领导一个团队并与他们日常密切合作。她还代表中层管理,负责制定战略和做出战术选择,并在一定程度上参与高级领导工作。她的大部分工作涉及管理预算和人员。如果有什么能够简化这个过程,她通常会很感兴趣。Masha 不希望浪费组织的资金,因为那可能直接影响到员工的工作。
目标
她的主要目标是确保组织顺利运行,并确保预算保持平衡。
互动
作为领导者,Masha 需要准确的数据,并且需要能够信任那些提供数据的团队。这些数据可以是从 Pelé Product 提供的特性概念到交付的端到端周期时间,Diego Developer 提供的变更前置时间,或者 Steven Service 提供的平均修复时间(MTTR)。拥有这些数据有助于她理解在哪些方面集中精力和资源能带来最大的影响。
Masha 定期与财务运营人员合作,确保他们了解组织的支出和这些支出所带来的价值。
需求
她需要在一个可以查看并做出良好决策的地方获取准确数据。这通常意味着她会从商业智能系统中获取信息。为了有效使用这些工具,她需要明确组织的目标,以便收集正确的数据,帮助她了解团队在实现这些目标的进展情况。
她还需要确保她所负责的团队拥有正确的数据和工具,以便在各自的领域中表现出色。
痛点
高故障率和长时间的恢复通常导致她不得不与客户沟通并道歉。玛莎非常讨厌这些电话!
云系统的可视化不足是一个特别的担忧。玛莎有太多由于缺乏监控而导致巨大超支的恐怖故事;她宁愿把这些预算花在更有用的地方。
你现在了解了使用可观察性数据的客户,以及你将使用的数据类型以满足他们的需求。由于本书的主要焦点是 Grafana 作为底层技术,让我们现在来介绍构成 Grafana 技术栈的工具。
介绍 Grafana 技术栈
Grafana 诞生于 2013 年,当时一位开发者正在寻找一种新的用户界面来显示 Graphite 的度量数据。最初从 Kibana 分支出来,Grafana 项目的开发旨在让用户能够快速构建对组织有价值的互动式仪表板。2014 年,Grafana Labs成立,核心价值是通过对开源项目的强力承诺建立可持续的商业模式。基于这个基础,Grafana 已经成长为一家强大的公司,支持超过 100 万个活跃安装。Grafana Labs 是开源项目的重要贡献者,从他们自己的工具到广泛采用的技术如 Prometheus,近期还积极参与如 OpenTelemetry 等热门项目。
Grafana 提供了许多工具,我们将其分为以下几类:
-
核心 Grafana 技术栈:LGTM和Grafana Agent
-
Grafana 企业插件
-
事件响应工具
-
其他 Grafana 工具
让我们在接下来的章节中探索这些工具。
核心的 Grafana 技术栈
核心 Grafana 技术栈由 Mimir、Loki、Tempo 和 Grafana 组成;常用缩写 LGTM 来指代这个技术栈。
Mimir
Mimir是一个时间序列数据库(TSDB),用于存储度量数据。它使用低成本的对象存储,例如 S3、GCS 或 Azure Blob Storage。Mimir 于 2022 年 3 月首次宣布公开发布,是我们在这里讨论的四个产品中最年轻的,值得一提的是,Mimir 最初是从另一个项目 Cortex 分叉出来的,Cortex 始于 2016 年。Cortex 的部分功能也构成了 Loki 和 Tempo 的核心。
Mimir 是一个完全兼容 Prometheus 的解决方案,旨在解决存储和搜索大量度量数据时遇到的常见扩展性问题。在 2021 年,Mimir 在负载测试中达到了 10 亿个活跃时间序列。活跃时间序列是指在过去 20 分钟内报告了样本的度量,并且具有值和唯一标签的度量数据。我们将在第五章中更详细地探讨 Mimir 和 Prometheus。
Loki
Loki 是一套完整功能的日志堆栈组件。Loki 使用低成本的对象存储,如 S3 或 GCS,并且仅索引标签元数据。Loki 于 2019 年 11 月进入正式发布阶段。
日志聚合工具通常使用两种数据结构来存储日志数据。一种是包含原始数据位置引用的索引,并配有可搜索的元数据,另一种是将原始数据以压缩形式存储。Loki 与许多其他日志聚合工具不同,它保持索引数据相对较小,并通过水平扩展查询组件来扩展搜索功能。选择最佳索引字段的过程将在第四章中讨论。
Tempo
Tempo 是一个高扩展性分布式追踪遥测的存储后端,旨在对读取路径的 100% 进行采样。像 Loki 和 Mimir 一样,它利用低成本的对象存储,如 S3、GCS 或 Azure Blob 存储。Tempo 于 2021 年 6 月进入正式发布阶段。
当 Tempo 发布 1.0 版本时,它在持续处理超过 200 万个跨度每秒(大约每秒 350 MB)的负载下进行了测试。Tempo 还提供了在数据跨度被摄取时生成度量指标的功能;这些指标可以写入任何支持 Prometheus 远程写入的后端。Tempo 在第六章中有详细介绍。
Grafana
Grafana 自 2014 年以来一直是数据可视化的基础工具。它支持连接各种数据源,从时间序列数据库(TSDB)到关系型数据库,甚至其他可观察性工具。Grafana 提供了超过 150 个数据源插件。Grafana 拥有一个庞大的社区,用户使用它进行各种不同的目的。该社区支持超过 6,000 个仪表板,意味着大多数现有技术都有一个起点,且可以在最短时间内实现价值。
Grafana Agent
从许多地方收集遥测数据是可观察性的基本方面之一。Grafana Agent是一组用于收集日志、指标和追踪的工具。Grafana 与许多其他收集工具有很好的集成。不同的收集工具有不同的优缺点,这不是我们在本书中讨论的话题。我们将在本章后面以及在第二章中介绍该领域的其他工具,以帮助你开始了解这个话题。我们还将在第十一章中简要讨论如何构建收集基础设施。
Grafana 堆栈是一个出色的开源软件集合,专为可观察性设计。Grafana Labs 对开源的承诺得到了优秀企业插件的支持。现在,让我们来探索这些插件。
Grafana 企业插件
作为 Cloud Pro、Cloud Advanced 和 Enterprise 许可套餐的一部分,Grafana 提供企业插件。这些插件是任何 Grafana 付费订阅的一部分。
企业数据源插件允许组织从他们可能使用的许多其他存储工具中读取数据,包括软件开发工具如GitLab和Azure DevOps,以及商业智能工具如Snowflake、Databricks和Looker。Grafana 还提供了从许多其他可观察性工具中读取数据的工具,这使得组织能够建立全面的运营覆盖,同时为各个团队提供他们所使用工具的选择。
除了数据源插件外,Grafana 还提供了日志、指标和追踪的高级工具。这些工具包括日志数据的访问策略和令牌,以保护敏感信息,深入的健康监控用于云堆栈的摄取和存储,以及租户管理。
Grafana 事件响应与管理
Grafana 在事件响应与管理(IRM)领域提供了三款产品:
-
IRM 的基础是警报规则,可以通过消息应用、电子邮件或 Grafana OnCall 进行通知。
-
Grafana OnCall提供了一种值班排班管理系统,将警报分组和升级路由集中管理。
-
最后,Grafana Incident提供了聊天机器人功能,可以设置必要的事件空间,收集事件后评审过程的时间线,甚至可以直接通过消息服务管理事件。
这些工具将在第九章中更详细地介绍。现在让我们来看看其他一些重要的 Grafana 工具。
其他 Grafana 工具
Grafana Labs 继续在可观察性领域保持领先地位,并收购了多家公司,以发布补充我们已经讨论过的工具的新产品。现在,让我们来讨论一些这些工具。
Faro
Grafana Faro 是一款可以添加到前端 web 应用程序中的 JavaScript 代理。该项目通过收集浏览器的遥测数据来实现真实用户监控(RUM)。通过将 RUM 集成到后端应用程序和基础设施已被监控的环境中,观察者能够跨越整个应用栈的数据。Faro 默认支持收集五个核心网页性能指标,以及其他几个重要信号。Faro 于 2022 年 11 月开始广泛发布。我们在 第十二章 中更详细地介绍了 Faro。
k6
k6 是一款负载测试工具,提供了一个可以在自有基础设施中运行的打包工具以及一个云端 软件即服务(SaaS)解决方案。负载测试,尤其是在 CI/CD 流水线中的测试,能够帮助团队了解应用在负载下的表现,并评估优化和重构的效果。与其他详细分析工具(如 Pyroscope)配合使用,可以大大提升团队中非技术成员的可见性和可访问性。该项目始于 2016 年,并于 2021 年 6 月被 Grafana Labs 收购。k6 的目标是让性能测试变得简单且可重复。我们将在 第十三章 中更深入探讨 k6。
Pyroscope
Pyroscope 是 Grafana Labs 最近收购的一个项目,于 2023 年 3 月加入。Pyroscope 是一款能够让团队进行持续性能分析的工具,能够监控应用程序对系统资源(如 CPU、内存等)的使用情况。Pyroscope 宣称,通过大约 2-5% 的性能开销,它能够每 10 秒就收集一次样本。Phlare 是 Grafana Labs 于 2022 年启动的项目,这两个项目现已合并。我们在 第十三章 中会更详细地讨论 Pyroscope。
现在,了解了 Grafana Labs 提供的不同工具后,让我们来看一些其他可用的替代方案。
Grafana 堆栈的替代方案
监控和可观察性领域充满了各种开源和闭源解决方案,像 ps 和 top 这样的工具可以追溯到 70 和 80 年代。我们不会试图列出所有工具;我们的目标是为那些好奇、想要探索,或者需要快速参考可用工具的人提供灵感(正如作者曾多次做过的那样)。
数据收集
这些是可以用来从源头收集遥测数据的代理工具:
| 工具名称 | 遥测类型 |
|---|---|
| OpenTelemetry Collector | 指标、日志、追踪 |
| FluentBit | 指标、日志、追踪 |
| Vector | 指标、日志、追踪 |
| 特定厂商代理(详见 数据存储、处理和可视化 部分,获取扩展列表) | 指标、日志、追踪 |
| Beats family | 指标、日志 |
| Prometheus | 指标 |
| Telegraf | 指标 |
| StatsD | 指标 |
| Collectd | 指标 |
| Carbon | 指标 |
| Syslog-ng | 日志 |
| Rsyslog | 日志 |
| Fluentd | 日志 |
| Flume | Logs |
| Zipkin Collector | Traces |
表 1.2 – 数据采集工具
数据采集只是可观察性数据的提取、转换和加载过程中的一部分。接下来的部分将介绍转换和加载数据的工具。
数据存储、处理和可视化
我们将数据处理、存储和可视化归为一类,因为它们之间经常有很多交集。某些工具还提供安全监控,与之密切相关。然而,由于这一主题超出了本书的范围,我们选择不包含仅涉及安全领域的工具。
| 工具名称 | 工具名称 | 工具名称 |
|---|---|---|
| AppDynamics | InfluxDB | Sematext |
| Aspecto | Instana | Sensu |
| AWS CloudWatch & CloudTrail | Jaeger | Sentry |
| Azure Application insights | Kibana | Serverless360 |
| Centreon | Lightstep | SigNoz |
| ClickHouse | Loggly | SkyWalking |
| Coralogix | LogicMonitor | Solarwinds |
| Cortex | Logtail | Sonic |
| Cyclotron | Logz.io | Splunk |
| Datadog | Mezmo | Sumo Logic |
| Dynatrace | Nagios | TelemetryHub |
| Elastic | NetData | Teletrace |
| GCP Cloud Operations Suite | New Relic | Thanos |
| Grafana Labs | OpenSearch | Uptrace |
| Graphite | OpenTSDB | VictoriaMetrics |
| Graylog | Prometheus | Zabbix |
| Honeycomb | Scalyr | Zipkin |
表 1.3 – 数据存储、处理和可视化工具
在充分理解了该领域内可用的工具后,我们现在来看看如何部署 Grafana 提供的工具。
部署 Grafana 栈
Grafana Labs 完全拥抱其作为开源软件提供商的历史。LGTM 栈及大多数其他组件都是开源的。有一些增值组件是企业订阅的一部分。
作为 SaaS 服务,Grafana Labs 提供 Loki、Mimir 和 Tempo 的存储访问,并且支持 Grafana 的 100 多个外部数据源集成。作为 SaaS 客户,您还可以轻松访问可能使用的其他各种工具,并可以在一个统一的界面中展示它们。SaaS 服务使组织能够利用一个功能全面的可观察性平台,而无需承担运行该平台和获取服务级别协议的运营负担。
除了为您管理平台,您还可以在组织的基础设施上运行 Grafana。Grafana 提供了几种格式的软件包,适用于 Linux 和 Windows 部署,并且还提供容器化版本。Grafana 还为每个工具提供了 Helm 和 Tanka 配置封装。由于 SaaS 版本容易开始并且有免费的层级,本书将主要集中在 SaaS 服务上。我们将在第十一章和第十四章中探讨一些本地安装的领域,这两章分别涉及 DevOps 流程的架构和支持。
总结
在本章中,你了解了监控和可观察性,它们的相似之处以及不同之处。巴拿马运河的 Agua Clara 闸门作为可观察性概念在实践中的简化示例。关键要点是要明白,即使系统为重大问题产生了警报,使用相同的数据仍然可以观察并调查其他潜在问题。
我们还讨论了可能使用可观察性系统的客户。当我们探讨一个概念以及如何实施它时,这些客户将在本书中被多次提及。
最后,我们介绍了完整的 Grafana Labs 堆栈,现在你应该对每个产品的不同用途有了较好的理解。
在下一章中,我们将介绍如何为类似 Diego 和 Ophelia 角色的读者添加应用程序或基础设施组件的监控基础知识。
第二章:工具化应用程序和基础设施
上一章介绍了可观察性,并通过计算机领域外的示例帮助你对该主题有了一个通用的理解。在本章中,我们将在这些示例的基础上,提供应用程序和基础设施工具化的高级概述。我们将查看系统生成的数据,并了解这些数据如何与不同的遥测类型和常用协议相适应。我们还将探索用于流行编程语言的广泛使用的库,这些库简化了应用程序的工具化过程。最后,我们将涵盖来自基础设施组件、操作系统和网络设备的更传统的遥测收集。这将使你了解今天仍在运行的应用程序和 Kubernetes 工作负载的组成部分。本章面向各类技术能力的读者,且不需要特定的技术背景。了解可观察性术语(例如:日志、指标、跟踪和工具化)将有所帮助。其目的是提供技术领域的概述,并作为一个有价值的资源,当你在使用可观察性解决方案时,可以快速查阅。
在本章中,我们将探讨以下介绍性内容:
-
常见日志格式
-
指标协议和最佳实践
-
跟踪协议和最佳实践
-
使用库进行高效的工具化
-
基础设施数据技术
常见日志格式
日志文件是计算机系统的标准组件,是软件开发人员和运维人员(在我们的例子中分别是 Diego 和 Ophelia)必不可少的工具。日志支持基础设施的性能和容量监控、软件中的错误检测、根本原因分析、用户行为追踪等功能。没有完美的日志格式,因此日志的外观并不重要,但遵循某些指南会在你需要分析日志时为未来的自己带来帮助。在本节中,我们将了解不同的日志格式以及如何使用数据。日志格式定义了日志文件的外观,并应解释如何解读数据。
日志格式通常会标明它们是结构化还是非结构化,所使用的数据类型,以及是否使用了任何编码或分隔符。我们将首先探索结构化日志格式,然后在接下来的章节中更详细地查看示例日志格式。
结构化、半结构化和非结构化日志
如前所述,日志的格式并不重要,您可以使用结构化、半结构化或非结构化的格式。但是,在设计和构建可观察性解决方案时,理解您正在使用的日志格式非常重要。这确保了您可以有效地导入、解析和存储数据。如果您已经熟悉第一章中的角色,您会知道这些日志将由谁使用以及用途是什么。
结构化日志
name=Diego 或 city=Berlin。
下面是结构化日志格式的一个示例:
{
"timestamp": "2023-04-25T12:15:03.006Z",
"message": "User Diego.Developer has logged in",
"log": {
"level": "info",
"file": "auth.py",
"line": 77
},
"user": {
"name": "diego.developer",
"id": 123
},
"event": {
"success": true
}
}
结构化日志的一个额外好处是,您可以使用诸如 JSON schema 等工具验证数据与架构的一致性。这为对架构进行版本控制更改提供了可能性,而这正是日志和事件总线技术交集的地方。
半结构化日志
半结构化日志旨在弥合非结构化和结构化之间的差距,因此可能会相当复杂。它们设计上易于人类阅读,同时也有架构使机器能够处理它们。它们具有复杂的字段和事件分隔符,并且通常带有定义的模式以帮助导入和解析。解析通常使用正则表达式或其他代码完成。
非结构化日志
非结构化日志通常指的是以文本格式呈现的日志条目,这种格式易于人类阅读,但对机器处理来说较为困难。它们通常通过颜色编码和空格来改善展示和可读性。正是这种展示方式使得机器难以处理这些日志。正确解析和拆分数据会导致事件与其标识元数据之间的断裂。非结构化日志需要一些定制的解析,这通常需要对数据有深入的了解,并且在导入数据时常常会给工程师(Ophelia)带来额外的工作。这也带来了技术上的责任;对日志保持一致性的依赖限制了开发者对日志的修改,或者有可能导致解析和报告非结构化日志时容易出现故障。
为了帮助机器处理非结构化日志,封装防止像堆栈跟踪这样的条目在不适当的位置被拆分。
以下是一个多行日志的示例,采用了寻找换行符的简单封装;这将在日志系统中显示为四个独立的事件:
2023-04-25 12:15:03,006 INFO [SVR042] UserMembershipsIterable Found 4 children for 4 groups in 3 ms
Begin Transaction update record.
Process started.
Process completed.
基于事件开始时时间戳的封装,将确保日志正确存储以便检索。
在接下来的部分,我们将探讨今天系统中常见的日志格式。
示例日志格式
许多日志格式已在计算机系统中使用。所有这些格式的共同目标是呈现一个标准结构或字段集,用于记录计算机系统活动的关键信息。下表旨在提供一些更为显著的日志格式的简便参考:
| 格式 | 概述 |
|---|---|
| 通用事件 格式(CEF) | CEF 是 ArcSight 提供的一种开放式日志和审计格式,旨在提供一个简单的接口来记录与安全相关的事件。 |
| NCSA 通用日志 格式(CLF) | NCSA CLF 历史上用于 Web 服务器记录对服务器的请求信息。该格式通过 CLF 扩展,包含有关浏览器(用户代理)和来源的额外信息。 |
| W3C 扩展日志 文件格式 | W3C 扩展日志文件格式是 Windows Internet Information Services 服务器(Web 服务器)常用的日志格式。 |
| Windows 事件日志 | Windows 事件日志是 Windows 操作系统使用的标准日志格式。这些日志记录系统上发生的事件,并按系统、应用程序、安全、设置和转发事件进行分类。 |
| JavaScript 对象 表示法(JSON) | JSON 是一种开放标准文件格式,非常适合轻松解析结构化日志事件。 |
| Syslog | Syslog 是一种标准,广泛用于许多硬件设备,如网络、计算和存储设备,也被 Linux 内核用于日志记录。 |
| Logfmt | Logfmt 没有定义的标准,但它是一种广泛使用的易于阅读的结构化日志格式。 |
表 2.1 – 日志格式概述
让我们更详细地了解这些格式。
CEF
由 ArcSight 开发,旨在满足 安全信息和事件管理(SIEM)用例,CEF 是一种结构化的基于文本的日志格式。使用 UTF-8 编码,该格式包含前缀、CEF 头部以及包含额外丰富数据的正文。
下表展示了 CEF 格式的日志部分:
| 日志部分 | 描述 |
|---|---|
| 前缀 | 它结合了事件时间戳和源主机名。 |
| CEF 头部 | 它结合了以下几项元数据:
-
软件版本
-
厂商名称
-
产品名称
-
产品版本
-
产品事件类别标识码
-
事件名称
-
事件严重性
|
| 正文 | 它包含一个键值对列表 |
|---|
表 2.2 – CEF 格式
这是一个 CEF 日志事件的示例:
CEF:0|Security Provider|Security Product|Version|123|User Authenticated|3|src=10.51.113.149 suser=diego target=diego msg=User authenticated from 1001:db7::5
NCSA CLF
作为 Web 服务器使用的最古老的日志格式之一,NCSA CLF 长期以来一直是最常见和最知名的日志格式。它具有固定格式的文本结构,因此无法定制。
这是 NCSA CLF 字段列表:
-
远程主机地址
-
远程日志名称
-
用户名
-
时间戳
-
请求和协议版本
-
HTTP 状态码
-
发送的字节数
在日志中缺失数据时,连字符充当占位符。无法支持的字符会被 + 符号替代。
这是一个 NCSA CLF 日志的示例:
127.0.0.1 user-identifier diego [25/Apr/2023:12:15:03 -0000] "GET /apache_pb.gif HTTP/1.1" 200 2326
W3C 扩展日志文件格式
微软的互联网信息服务器日志格式 W3C 是一种结构化但可配置的格式。完全控制包含的字段,确保日志文件包含最相关的数据。信息或流向的标识通过字符串前缀表示:服务器(S)、客户端(C)、服务器到客户端(SC)和客户端到服务器(CS)。
以下是 W3C 扩展日志文件格式字段列表:
-
时间戳
-
客户端 IP
-
服务器 IP
-
URI 主体
-
HTTP 状态码
-
发送的字节数
-
接收的字节数
-
耗时
-
版本
以下是一个 W3C 日志示例:
#Software: Internet Information Services 10.0
#Version: 1.0
#Date: 2023-04-25 12:15:03
#Fields: time c-ip cs-method cs-uri-stem sc-status cs-version
12:15:03 10.51.113.149 GET /home.htm 200 HTTP/1.0
微软 Windows 事件日志
微软 Windows 操作系统自带一个复杂的结构化日志系统,用于捕获与操作系统中特定事件相关的数据。Windows 事件日志有四个常见的类别——系统、应用程序、安全性和设置——以及一个用于转发事件的特殊类别。
每个事件日志也有五种不同的类型:信息、警告、错误、成功审计和失败审计。Windows 事件日志是使用中最详细的日志格式之一。它通常包括时间戳、事件 ID、用户名、主机名、消息和类别等详细信息,这些信息在诊断问题时非常有价值。Windows 事件 ID 有文档记录并可搜索,因此你可以轻松获取关于日志事件的详细信息;它们被分为不同的类别,缩小了事件发生的范围,这使得调试非常精确。
以下是一个修剪过的微软 Windows 事件日志示例:
An account was successfully logged on.
Subject:
Security ID: SYSTEM
Account Name: DESKTOP-TMC369$
Account Domain: WORKGROUP
Logon ID: 0xE37
Logon Information:
New Logon:
Security ID: AD\DiegoDeveloper
Account Name: diego.developer@themelt.cafe
Account Domain: AD
Logon ID: 0xEC4093F
Network Information:
Workstation Name: DESKTOP-TMC369
JSON
作为今天新兴但最常用的日志格式之一,JSON 是一种由多个键值对构成的结构化格式。使用 JSON,数据可以嵌套成不同的层次,同时保持格式易于阅读。此外,JSON 可以表示不同的数据类型,如字符串、数字、布尔值、空值、对象和数组。
以下是一个 JSON 日志文件示例:
{
"timestamp": "2023-04-25T12:15:03.006Z",
"message": "User Diego.Developer has logged in",
"log": {
"level": "info",
"file": "auth.py",
"line": 77
},
"user": {
"name": "diego.developer",
"id": 123
},
"event": {
"success": true
}
}
Syslog
Syslog 作为许多年来的标准日志格式,并且至今仍被广泛使用,是一种定义好的标准,用于创建和传输日志。514和6514是常见的端口,后者用于加密。
Syslog 消息格式结合了标准化的头部和包含日志正文的消息。
以下是一个 Syslog 日志示例:
Apr 25 12:15:03 server1 sshd[41458] : Failed password for diego from 10.51.113.149 port 22 ssh2
Logfmt
Logfmt 是一种广泛使用的日志格式,既适合人类阅读又具有结构化,计算机和人类都能读取。Logfmt 格式的日志行由任意数量的键值对组成,便于解析。由于没有标准,它很容易扩展,开发人员可以简单地向输出中添加更多键值对。
以下是一个 Logfmt 日志示例:
level=info method=GET path=/ host=myserver.me fwd="10.51.113.149" service=4ms status=200
探索度量类型和最佳实践
指标和日志是软件开发人员(Diego)和运维人员(Ophelia)的基本工具,为他们提供应用程序和系统状态的指示器。资源使用数据非常适合监控捕捉数值数据的指标。资源类型有很多种,但一些好的例子包括 CPU 或 RAM 使用率、队列中消息的数量以及接收到的 HTTP 请求数量。指标通常会生成,并且可以轻松地通过标签、属性或维度进行增强,使它们在搜索时非常高效,并且在判断某些情况是否异常或不同于平时时非常理想。
一个指标通常具有以下字段:
-
名称:唯一标识该指标
-
数据点值:存储的数据根据指标类型有所不同
-
维度:支持分析的附加增强标签或属性
指标捕捉它们所代表的数据的行为。例如,CPU 使用率将在 0% 到 100% 之间波动,而接收到的 HTTP 请求的数量可能会无限增加。在接下来的部分,我们将查看指标类型,它们允许我们捕捉收集到的指标的行为。
指标类型
指标在特性和结构上有所不同。常见的四种指标类型从简单的单值到更复杂的值:
-
计数器:该指标表示上次增量值。它可能是上次记录的增量变化,也可能是自记录开始以来的总增量。
以下是该指标的一些示例:
-
提供的请求数量
-
完成的任务
-
报告的错误
如何将值重置为零取决于用于收集它们的协议,因此在你的用例中考虑这一点非常重要。StatsD 实现会在每次刷新值时重置计数器,而 Prometheus 会在应用进程重启时重置计数器。
-
-
仪表:仪表指标是状态的快照,可以用来测量某些持续报告的事物。因此,它通常通过在一定时间段内汇总求和、平均值、最小值或最大值来变得更有用。
以下是该指标的一些示例:
-
温度
-
队列中的项目
-
磁盘空间使用情况
-
并发请求数量
和计数器一样,仪表的定义在实现上有所不同,因此请确保验证你选择的协议将如何报告仪表指标。
-
-
_count(表示所有测量值的总和)、_sum(表示所有值的总和),以及几个桶,它们记录的事件数小于或等于(le)定义值。定义可能在实现上有所不同——例如,Prometheus 有一个
histogram_quantile函数,可以用来从直方图指标计算百分位数。 -
_count和_sum度量以及几个分组。与直方图不同,这些分组是分位数,值表示在该时间点上该分位数的值。例如,0.99 的分位数和 3.2148 的值表示 99% 的采样数据小于 3.2148。
再次强调,定义可能因实现而有所不同,因此从度量中明确你的目标,以确保所选择的协议支持这些功能。值得注意的是,在 Prometheus 中,总结性度量在现代系统中有一个显著的缺点,即不能跨多个来源进行聚合。
这些度量类型之间有一些明显的区别,正如我们将在接下来的章节中讨论的那样。
比较度量类型
以下表格一般性地描述了每种类型。在查询时,当你接近度量标准的采纳时,这提供了一个有用的参考:
| 考虑因素 | 计数器 | 仪表 | 直方图 | 总结 |
|---|---|---|---|---|
| 结构 | 简单 | 简单 | 复杂 | 复杂 |
| 可以增加和减少 | 否 | 是 | 否 | 否 |
| 是近似值 | 否 | 否 | 是 | 是 |
| 可以计算分位数 | 否 | 否 | 是 | 是 |
| 可以使用速率函数 | 是 | 否 | 否 | 否 |
可以使用 prometheus histogram_quantile 函数查询 |
否 | 否 | 是 | 否 |
| 可以跨多个系列进行聚合 | 是 | 是 | 是 | 否 |
表 2.3 – 度量类型比较
以下表格提供了一些参考示例,列出了预期的类型和值:
| 度量类型 | 数据字段 | 值 |
|---|---|---|
| 计数器 | 最后增量 | 15 |
| 仪表 | 最后值 | 25.4 |
| 直方图 | 最小值 | 0 |
| 最大值 | 100 | |
| 计数 | 10 | |
| 间隔 | 20 | |
| 0-20 | 1 | |
| 20-40 | 2 | |
| 40-60 | 4 | |
| 60-80 | 2 | |
| 80-100 | 1 | |
| 总结 | 最小值 | 1.2ms |
| 最大值 | 4.23ms | |
| 计数 | 10 | |
| 总和 | ||
| 百分位数/分位数 | ||
| P90 | 2.98ms | |
| P95 | 3.76ms | |
| P99 | 4.23ms |
表 2.4 – 度量类型示例数据
现在我们已经了解了不同类型的度量标准,让我们来看一下用于传输度量标准的不同技术。
度量协议
度量协议 是一组用于对应用程序进行仪表化的工具和库,数据格式用于传输,客户端用于收集数据,通常还包括存储和可视化工具。以下表格描述了一些当前使用的常见协议:
| 度量协议 | 特性 |
|---|
| StatsD | 它支持以下内容:
-
计数器
-
仪表
-
定时器
-
直方图
-
米
|
| DogStatsD | DogStatsD 实现了 StatsD 协议,并添加了几个 Datadog 特有的扩展:
-
直方图度量类型
-
服务检查
-
事件
-
标签
|
| OpenTelemetry 协议 (OTLP) | 它支持以下内容:
-
计数器
-
仪表
-
直方图
-
总结(遗留支持)
|
| Prometheus | 它支持以下内容:
-
计数器
-
仪表
-
累积直方图
-
总结
|
表 2.5 – 常见度量协议及其特性
指标非常强大,但一些陷阱可能会让人掉进误区。其中一些可能导致昂贵的错误。为了避免这些陷阱,让我们讨论一些最佳实践。
实施指标的最佳实践
将指标引入你的服务是获取它们在实际情况下行为的大量可见性的一个非常好的方法。以下最佳实践来自我们在指标方面的经验,将帮助你管理范围膨胀、成本以及将指标与追踪连接起来:
-
设定目标:明确从指标中得到什么样的目标。我们已经讨论过指标协议之间的实现差异——如果你期望以某种方式使用指标,但没有考虑到细微差别,这会产生很大的影响。
这也将帮助你定义服务级指标(SLIs)和服务级目标(SLOs),它们将在第九章中派上用场,事件管理 通过警报管理。
-
管理基数:基数通常被定义为集合中唯一元素的数量。高基数可能提供更丰富、更有用的数据,但也会带来对监控性能的影响或增加存储成本。例如,如果你按服务器名称来划分你的指标,样本可能很小,也许只有几百个指标。如果与按用户来划分进行比较,可能会达到数百万个,生产的指标数量呈指数增长。这种增加直接影响负载和存储。
花时间了解可观测性后端的能力——如计费框架、限制、存储和性能等方面。
-
添加上下文:最近,Grafana 和 Open Telemetry 引入了通过示例来关联(建立共同标识符)指标与追踪的能力。它们能够快速可视化并将指标数据点与特定的追踪跨度关联,从而为你的数据提供更丰富的上下文和细节。
正如我们刚才讨论的那样,指标捕获来自单一服务的数值数据;然而,今天运作的系统可能由多个服务组成。分布式追踪是获取服务之间通信可见性的一种方式。让我们来看看追踪协议以及一些相关的最佳实践。
追踪协议和最佳实践
追踪,或更常见的术语分布式追踪,跟踪应用程序请求在系统各服务之间的传递。它允许你跟踪单个请求穿越整个系统,或查看跨请求的聚合数据,从而更好地理解分布式行为。
该功能为软件开发人员(Diego)、运维人员(Ophelia)和服务经理(Steven)提供了宝贵的工具,帮助理解对于故障排除至关重要的逻辑流。通过在代码中添加追踪来进行仪器化,能帮助你轻松定位几乎所有问题,或者至少能明确指出问题可能所在的位置。分布式追踪使用 spans 和追踪的概念来捕获这些数据。让我们更详细地研究这些概念。
Spans 和追踪
追踪记录是表示通过被观察系统的数据流或执行路径的父对象。每个追踪将包含一个或多个span记录,代表逻辑操作。追踪和 span 之间的关系如下图所示,可以将其视为 span 的有向无环图:

图 2.1 – 追踪与 span
一个追踪是由多个 span 拼接而成,通常会报告以下信息:
-
标识符:唯一标识追踪
-
名称:描述记录的总体工作
-
时间详细信息:提供完整追踪的开始和结束时间戳
一个 span 通常包含以下字段:
-
追踪标识符:建立追踪关系
-
标识符:唯一标识 span
-
父 span 标识符:建立父关系
-
名称:描述正在记录的工作
-
时间详细信息:提供开始和结束时间戳
如果调用操作未接收到追踪标识符,则将自动生成一个追踪标识符;每个应用程序将把追踪 ID 传递给下一个操作。
操作的开始和结束时间戳有助于识别哪个阶段消耗了最多的时间。您可以深入分析,识别对其他服务的依赖关系,以及它们如何影响整体追踪时间。
Span 通常可以有一些特定于实现协议的附加字段。根据您的使用案例进行调查,有助于为您的系统提供正确的诊断。
追踪协议
与所有技术一样,追踪的标准化花了一些时间,目前已经实现了几种协议。当前使用的一些常见协议如下表所示:
| 协议名称 | 特性 |
|---|
| OTLP | 它支持以下内容:
-
额外字段
-
Span 属性(关于操作的元数据)
-
上下文传播
-
Span 事件(有意义的时间点注释)
-
Span 链接(表示 span 之间的因果关系)
-
Span 类型(支持构建追踪的附加详细信息)
|
| Zipkin | 它支持以下内容:
-
额外字段
-
Span 标签(关于操作的元数据)
-
上下文传播
-
Span 注释(例如 OTLP 事件和有意义的时间点注释)
-
Span 类型(支持构建追踪的附加详细信息)
|
| Jaeger | 它支持两种格式 —— Jaeger Thrift 和 Jaeger Proto —— 特性相似。Jaeger Proto 已被弃用,转而支持 OTLP。它支持以下内容:
-
额外字段
-
Span 标签(关于操作的元数据)
-
上下文传播(仅 Thrift 支持;Proto 不支持)
-
Span 日志(有意义的时间点注解)
-
Span 引用(表示 span 之间的因果关系)
-
Span 类型(类似于 OTLP,这作为一种特殊类型的 span 标签存储)
|
表 2.6 – 分布式追踪协议和特性
实施分布式追踪可能是一项艰巨的任务,接下来我们将讨论一些最佳实践,帮助你避免常见的错误和问题。
设置分布式追踪的最佳实践
到目前为止,我们已经描述了追踪如何帮助你解决问题。然而,在生成追踪时,值得考虑额外的系统可见性与成本和性能影响之间的平衡。接下来让我们讨论一些在实施追踪时应考虑的最佳实践。
性能
生成追踪信息的过程可能会在应用层面产生性能开销。结合自动仪器监控减少的控制力,这个问题可能会加剧。
这里有一些需要考虑的可能影响:
-
增加的延迟
-
内存开销
-
启动时间较慢
一些较新的可观察性代理解决了许多问题,提供了可配置选项。例如,OpenTelemetry Collector 提供了一种采样配置,允许提交 0% 到 100% 的 span 到收集工具。此采样实现还会通知任何下游服务,父级采样了它的 span,从而确保收集到完整的追踪。
成本
增加的网络和存储成本可能成为一个因素,在设计你的可观察性解决方案时需要考虑作为限制条件。然而,这取决于你的可观察性后端以及你是否在数据传输过程中进行额外的处理或过滤。
缓解措施如下:
-
采样:仅发送一定比例的追踪
-
过滤:限制哪些追踪被传输和存储
-
保留:设置最佳的数据存储时长
准确性
为了确保追踪的一个主要好处得以实现,必须确保上下文传播正常工作。如果操作之间没有建立关系,span 将会在多个追踪中断开。验证并解决这个问题将提高追踪的可用性和采用率,从而加速问题解决。
对于大多数代码,使用库是为了让开发人员能够专注于编写为组织创造价值的代码。现代库的使用将帮助你快速进行仪器监控,从而能够开始使用从应用程序收集的数据。接下来我们将探讨这一点。
使用库来高效地进行仪器监控
将你的应用程序代码进行仪器化,以发出日志、度量和追踪的遥测数据可能会很复杂、耗时,并且难以维护。解决这个问题的主要方法有两种——自动化仪器化和手动仪器化——并且有许多 SDK 和库可供支持。以下是它们的简要概述:
-
自动化仪器化:自动化仪器化是最简单实现的方式,但在构建可观察性平台时,往往缺乏所需的控制级别。在非常短的时间内,它将为你的应用程序提供可视化,并帮助你开始回答可观察性相关的问题。如果没有仔细的配置和设计,这可能会导致性能和成本等问题,最坏的情况是让可观察性平台变得无用。
该方法取决于编程语言;例如,Java 通常使用代码操作(在编译或运行时),而 Python 和 JavaScript 则通常使用猴子补丁(在运行时动态更新行为)。
-
手动仪器化:手动仪器化可能相当复杂,具体取决于被仪器化的系统。它需要对应用程序代码有深入的了解,优点是能够精确指定你需要的遥测数据。此外,你还需要了解你正在使用的可观察性 API。尽管 SDK 和库简化了这一过程,但仍然需要做大量的工作来理解其实现。
如果你有兴趣进一步阅读应用程序仪器化的内容,Alex Boten 的《Cloud-Native Observability with OpenTelemetry》一书中有一个关于该主题的精彩章节,出版商为 Packt Publishing。
现在我们已经了解了各种库如何进行仪器化,接下来我们来看一下在不同语言中常用的一些库。
不同编程语言的流行库
多年来已经有很多遥测解决方案、SDK 和库;然而,近年来,大家共同努力致力于支持 OpenTelemetry 标准。其目标是提供一套标准化的供应商中立的 SDK、API 和工具,用于接收、转换和传输数据到可观察性后端平台,这带来了明显的好处。在本节中,我们将关注 OpenTelemetry 库,重点是目前的改进之处。然而,研究哪些适合你的用例是很重要的。这个集中的开发努力的一个缺点是它创造了一个快速变化的环境,因此你需要关注发布的稳定性并监控变化和改进。
以下是一些可用的仪器化库:
| 语言 | SDK 和库 | 备注 |
|---|---|---|
| JavaScript | OpenTelemetry JavaScript SDK | 提供了多个资源和示例,涵盖了 Node.js 和浏览器实现。 |
| JavaScript | OpenTelemetry JavaScript Contrib | 这是一个额外的 OpenTelemetry JavaScript 存储库,用于存放那些不属于核心存储库和核心 API、SDK 分发包的贡献。 |
| Python | OpenTelemetry Python SDK | 写作时,追踪和指标已经稳定,日志处于实验状态。 |
| Python | OpenTelemetry Python Contrib | 这是一个额外的 OpenTelemetry Python 存储库。写作时,Contrib 库处于 beta 阶段,并且在积极开发中。 |
| Java | OpenTelemetry Java SDK | 有一长串支持的库和框架,且提供了良好的文档,帮助你入门。 |
| Java | Spring Boot/Micrometer | 从 Spring Boot 3 开始,Micrometer 的默认导出器是 OTLP。 |
表 2.7 – 常见的遥测库和 SDK
应用程序只是我们今天使用的计算机系统的一部分。我们的基础设施组件,例如交换机、服务器、Kubernetes 集群等,同样需要被观察。我们将在下一节讨论如何进行这些观察。
基础设施数据技术
到目前为止,我们集中讨论了适用于云技术和容器化平台的实现。所有这些抽象背后是物理组件,包括运行工作负载的服务器、处理通信的网络和安全设备、以及保持系统运行的电力和冷却组件。这些内容随着时间的推移并没有发生剧烈变化,日志和指标所报告的遥测数据也是如此。接下来我们将看看这一领域常见的基础设施组件和标准。
常见的基础设施组件
基础设施可以大致分为几个广泛的类别,正如我们将在接下来的章节中讨论的那样。你可以收集的数据类型会根据组件类别的不同而有所变化。
计算或裸金属
服务器通常被称为 裸金属 或计算设备;它们是用于计算的物理设备。这些系统通常运行虚拟化的操作系统,这些操作系统可以收集服务器遥测数据。通常,你会在操作系统上运行一个代理,抓取指标或读取日志文件,然后将数据传输到接收器。通过服务器设备获得的数据不仅有助于诊断和响应问题,还能帮助预测可能出现的容量问题。这些设备通常也可以将数据发送到任何虚拟操作系统外部。
例如,以下是一些可以表明系统是否接近任何领域容量限制的遥测示例:
-
系统温度
-
CPU 利用率百分比
-
总体磁盘空间使用和剩余空间
-
内存使用和剩余内存
网络设备
网络和安全设备,如交换机和防火墙,通常具有通过 SNMP 向接收器发送监控信息的能力。防火墙通常可以将 Syslog 格式的日志发送到接收器。提供的遥测数据有助于诊断连接问题——例如,没有硬件提供的信息,延迟和吞吐量是很难调查的。
以下是一些遥测示例:
-
延迟
-
吞吐量
-
丢包
-
带宽
电源组件
提供电力或冷却功能的组件通常具有通过 SNMP 向接收器发送遥测数据的能力。一些较旧的组件会实现 Modbus 协议,并公开可以读取的寄存器,以获取度量信息。这个层级报告的遥测数据虽然简化,但在操作数据中心时是至关重要的。例如,如果你正在使用备用电源,你需要迅速做出反应,保护系统或触发其他缓解活动。
以下是一些遥测示例:
-
电源状态
-
备用电源状态
-
电压
-
功率
-
电流
由于基础设施组件已经使用多年,因此对数据结构和传输存在一些公认的标准。现在让我们来看看这些原始标准。
基础设施组件的常见标准
有一些已经确立的标准被基础设施组件使用,这些组件可能是你需要监控的。包括以下内容:
-
Syslog:Syslog 自 1980 年代以来就存在,并在基础设施组件中非常常见。它由 Eric Allman 作为 Sendmail 项目的一部分创建,很快就被采用并成为类 Unix 平台的标准日志记录解决方案。它因易于使用而广受欢迎。要使用 Syslog,您需要一个可接收数据的客户端,并且每个设备需要配置为将数据发送到该客户端。常见的客户端包括 RSyslog 和 Syslog-ng,OpenTelemetry Collector 也支持该协议。
Syslog 消息格式提供了一个结构化框架,允许组织提供供应商特定的扩展。作为其成功和长期存在的贡献,大多数现代可观测性工具提供商仍然提供接收 Syslog 消息的接口。然后,可以访问这些日志并与其他系统和应用程序的遥测数据一起分析。
-
简单网络管理协议(SNMP):作为 互联网工程任务组(IETF)定义的原始互联网协议族的一部分,SNMP 通常用于网络基础设施。该协议的很多部分与可观测性无关,但 SNMP Trap 允许设备将重要事件通知管理者。
SNMP 为网络设备提供了一种通用机制,以便在单一和多厂商的局域网或广域网环境中传递管理和特别是在本章背景下的监控信息。它与其他遥测接收器不同,因为它需要更多关于网络上设备的具体知识,并且需要针对指标收集进行特定的配置。以下是一些可以通过 SNMP 收集的数据示例:
数据类型 示例 收集的指标 网络数据 进程运行时间吞吐量 设备数据 内存使用率 CPU 使用率温度
表 2.8 – 示例 SNMP Trap 信息
你可能会在广泛的工程领域中遇到其他格式。我们在这里已经覆盖了许多常见的格式,并且希望能够为你提供有关在 Grafana 中使用遥测所需信息的指示。Grafana 几乎可以处理你能提供的任何内容。了解什么是重要的并为此做好准备,将帮助你在构建数据的可视化和告警时更加得心应手。现在,让我们快速回顾一下本章的内容。
总结
在本章中,我们探索了现代可观测性构建的基础。这将作为本书后续章节和你自己项目的简便参考和支持。首先,我们查看了常见的日志格式及其示例,这将帮助我们在第四章中进一步学习,使用 Grafana Loki 查看日志。接着,我们深入探讨了指标、它们的不同类型、一些示例协议,以及在设计基于指标的可观测性时需要考虑的最佳实践。本章所涵盖的内容将对第五章,使用 Grafana Mimir 和 Prometheus 进行指标监控有所帮助。然后,我们转向了跟踪和跨度,研究了当前的协议以及在构建高效、有效的基于跟踪的可观测性平台时需要考虑的一些最佳实践。本节为第六章,使用 Grafana Tempo 进行跟踪技术探讨奠定了基础。了解了可观测性的遥测后,我们学习了应用程序仪表化的内容,我们将在第三章中更深入了解,通过示例应用程序设置学习环境,以及后续章节中关于日志、指标和跟踪的具体内容。最后,我们还考虑了一些更传统的基础设施遥测。
在完成了应用程序和基础设施仪表化的概述后,我们现在可以开始玩转日志、指标和跟踪了。在下一章中,我们将启动并运行我们的学习环境。
第三章:使用演示应用程序设置学习环境
本章将指导你设置一个 学习环境,用于本书中的实际示例以及独立实验。由于 Grafana Labs 提供了免费层云服务,我们将使用该服务进行数据存储和搜索。为了生成丰富有用的数据,我们将使用 OpenTelemetry 演示应用程序。该演示应用程序部署了运行 OpenTelemetry Astronomy Shop 所需的服务。这些应用程序采用多种编程语言编写,并已进行仪器化以生成指标、日志和分布式追踪数据。此应用程序将帮助你直接与真实应用程序进行交互(包括通过负载生成器),并实时在 Grafana Labs 实例中查看观察性遥测数据。
在本章中,我们将涵盖以下主要主题:
-
介绍 Grafana Cloud
-
安装必备工具
-
安装 OpenTelemetry 演示应用程序
-
探索来自演示应用程序的遥测数据
-
故障排除 OpenTelemetry 演示应用程序
技术要求
我们假设你正在使用至少 Windows 10 版本 2004、macOS 版本 11 或相对较新的 Linux 安装(例如,Ubuntu 20.10 或更高版本);早期版本不受支持。我们将使用 OpenTelemetry Collector 版本 0.73.1 和 OpenTelemetry 演示版本 0.26.0。本章提供了这些组件的完整安装说明。
完成这些步骤所需的所有命令和配置文件都包含在 GitHub 仓库中,地址为 github.com/PacktPublishing/Observability-with-Grafana/tree/main/chapter3。你可以在 packt.link/GNFyp 查看本章的 代码实践 视频。
介绍 Grafana Cloud
Grafana Cloud 是一个托管的基础设施即服务观察性工具平台。它提供了快速创建基础设施的能力,用于接收和存储日志、度量和追踪数据,并且提供可视化数据的工具。我们使用 Grafana Cloud 来降低与本书内容互动所需的技术技能,尽管我们将介绍的所有 Grafana 开源组件也可以本地部署。
Grafana Cloud 提供免费访问。在本章中,我们将首先设置一个云账户,并熟悉工具的管理和使用。
重要提示
Grafana Labs 会定期推出更新。本章中的信息和截图基于 2023 年 10 月发布的 Grafana 版本 10.2。
设置账户
创建免费 Grafana Cloud 账户很简单。请按照以下步骤操作:
-
访问
www.grafana.com,然后点击 创建 免费账户。 -
使用以下任一方式注册
-
一个 Google 账户
-
一个 GitHub 账户
-
一个 Microsoft 账户
-
一个 Amazon 账户
-
一个电子邮件地址
-
-
选择一个团队 URL。这是用来访问您的 Grafana 实例的 URL。在我们的示例设置中,我们选择了
observabilitywithgrafana:

图 3.1 – 创建 Grafana stack
-
从可用列表中选择一个部署区域,然后等待几分钟以完成您的 Grafana 账户创建。
-
当账户创建完成后,您将看到一个名为 GET STARTED 的屏幕,如下图所示。我们鼓励您探索 Grafana 的各个屏幕,但在这次介绍中,您可以直接点击 I’m already familiar with Grafana:

图 3.2 – 开始使用 Grafana
然后点击左上角的 Grafana 图标返回到主屏幕,最后点击 Stacks,它位于欢迎信息的下方:

图 3.3 – 欢迎来到 Grafana Cloud
- 这将带您进入 Grafana Cloud 门户,界面如下所示。

图 3.4 – Grafana Cloud 门户
在我们设置本地数据生成环境之前,先花点时间探索一下 Grafana Cloud 门户和您的新 Grafana Stack 的基础内容。
探索 Grafana Cloud 门户
门户网站的首页展示了您的订阅和账单信息,以及有关您的单一 Grafana Stack 的详细信息。当您首次注册 Cloud Free 订阅时,您将获得 14 天的 Cloud Pro 试用访问权限。要访问您的 Grafana 实例,您需要点击 Grafana 部分中的 Launch 按钮。这将使您能够查看发送到 Grafana Cloud 的数据。
完整的 Grafana Stack 包括以下安装:
-
可视化:
- 一个 Grafana 实例
-
指标:
-
一个 Prometheus 远程写入端点
-
一个 Graphite 端点
-
一个 Mimir 后端存储实例
-
-
日志:
-
一个 Loki 端点
-
一个 Loki 后端存储实例
-
-
追踪:
-
一个 Tempo 端点
-
一个 Tempo 后端存储实例
-
-
告警:
- 一个用于管理基于 Prometheus 的告警的告警实例
-
负载测试:
- 一个 k6 云端运行器
-
性能分析:
-
一个 Pyroscope 端点
-
一个 Pyroscope 后端存储实例
-
让我们来看一下您可以在门户中访问的一些部分:
-
安全性:在此部分,您可以管理 访问策略 和 访问令牌、开放授权(OAuth)、安全声明标记语言(SAML)和 轻量级目录访问协议(LDAP)。
访问策略的范围是一个 领域;一个领域可以覆盖特定的 Stack,也可以覆盖整个组织。
-
支持:此部分通过 社区论坛 提供社区支持,并通过 支持票 和 与支持人员聊天 提供来自 Grafana Labs 的支持。
-
账单:账单部分是用于管理发票和订阅的地方。Cloud Free 订阅提供每月 10,000 个度量标准、50 GB 日志、50 GB 跟踪、50 GB 配置文件、三个 事件响应与管理 (IRM) 用户和 500 个 k6 虚拟用户小时 (VUh) 的配额。这个订阅对于我们在本书中使用的示例应用程序以及类似的小型演示和个人用途安装非常充足。对于更大的安装,Grafana Cloud 还提供了两个额外的套餐,Cloud Pro 和 Cloud Advanced。这些套餐提供对不同关键功能的访问,其中 Cloud Advanced 主要面向企业级安装。Grafana 根据不同领域的摄取量和活跃用户进行计费。Grafana 提供了一个非常易于使用的月度费用估算工具:

图 3.5 – Grafana 成本估算器
使用 Cloud Free 订阅,你将只能访问一个堆栈。如果你订阅了 Cloud Pro 或 Cloud Advanced,你将能够在你的账户中创建多个堆栈。这些堆栈可以位于不同的区域。
- 组织设置:在这里,你可以管理可以访问 Grafana Cloud 的用户。你还可以更新你的头像、组织名称以及你与社区共享的插件或仪表板。
现在你已经探索了 Grafana Cloud 门户,并且了解了如何管理 Grafana Cloud 账户,接下来让我们探索你云堆栈中的 Grafana 实例。
探索 Grafana 实例
与 Grafana Stack 提供的工具互动的主要方式是访问 Grafana 实例。该实例提供可视化工具,用于查看由其他 Grafana 堆栈或其他连接工具收集的数据。要访问你的 Grafana 实例,你可以点击 Cloud Portal 中的 启动 按钮:

图 3.6 – 启动 Grafana
为了更直接地访问,你可以使用基于帐户创建时选择的团队名称的直接 URL。例如,我们的示例账户的 URL 是 https://observabilitywithgraf``ana.grafana.net。
一旦你访问了 Grafana,你将看到一个主页,显示你当前的使用情况。导航是通过页面左上角的菜单进行的:

图 3.7 – Grafana 中的主要导航面板
让我们逐一讲解前面图中显示的菜单中不同的部分。
仪表板与收藏的仪表板
仪表板部分允许你在 Grafana 安装中创建、导入、组织和标记仪表板。在 仪表板下,你还可以访问 播放列表、快照、库面板 和 报告:
-
播放列表子部分让你管理按顺序显示的仪表板组,例如,在办公室的电视上。
-
快照标签让你能够拍摄一个仪表盘的快照并分享数据。这将使接收者能够比共享简单的屏幕截图更好地探索数据。
-
库面板提供了可重复使用的面板,可以在多个仪表盘中使用,以帮助提供标准化的 UI。
-
最后,报告功能允许你从任何仪表盘自动生成 PDF 并按预定计划发送给相关方。
星标仪表盘部分允许你通过将常用的仪表盘保存到菜单顶部来自定义界面。我们将在第八章中更全面地探讨如何使用仪表盘。
探索
探索是直接访问连接到 Grafana 实例的数据的方式。这是构建自定义仪表盘并探索数据以理解系统当前状态的基础。我们将在本章后面标题为从示例应用程序探索遥测数据的部分简要讨论这一点,之后将在第四章、第五章和第六章中详细介绍。
警报与 IRM
警报与 IRM部分包含了 Grafana 的警报管理、值班和事件系统用于 IRM,还包括机器学习能力和 SLO 服务。这些功能可以帮助识别系统中的异常(有关详细信息,请参见第九章):

图 3.8 – 警报与 IRM
警报管理(Alertmanager)允许团队管理触发警报的规则。它还允许团队控制警报通知的方式,并决定是否有任何预定的警报时间表。Grafana 的警报管理旨在通知特定团队其系统中的警报,并且已经通过许多组织的实际使用进行了验证。
值班和事件构成了 Grafana 的 IRM 工具包。它使组织能够接收来自多个监控系统的通知,管理排班和升级链,并提供关于已发送、已确认、已解决和已静默的警报的高级可视化。事件部分使组织能够启动事件处理。这些事件遵循预定义的流程,涉及正确的人员并与利益相关者进行沟通。一旦事件启动,Grafana 可以记录事件过程中关键时刻的内容,以便后续的事件后处理。值班和事件旨在帮助需要集中管理技术方面的问题和事件管理的组织。第九章将更详细地探讨这些工具并展示如何配置它们。
性能测试
性能测试区域是 k6 性能测试工具与 Grafana UI 集成的地方,允许团队管理测试和项目。k6 使团队能够在 CI/CD 流水线中使用与生产环境测试相同的性能测试工具。k6 将在 第十三章中详细介绍。
可观察性
可观察性部分将 Kubernetes 基础设施和应用监控整合在一起,并通过合成测试模拟应用中的关键用户旅程,同时结合前端 真实用户监控 (RUM) 和 Pyroscope 的 性能配置文件。通过结合这些数据源,您可以获得对产品当前性能的端到端视图。
连接
连接部分是一个管理区域,用于设置和管理 Grafana 与 160 多个数据源及基础设施组件之间的连接,这些数据源和组件可以连接并显示数据。一些可用连接的示例包括 Elasticsearch、Datadog、Splunk、AWS、Azure、cert-manager、GitHub、Ethereum 和 Snowflake。配置这些连接的页面如下图所示:

图 3.9 – 连接屏幕
管理
管理面板允许管理 Grafana 的许多方面,从插件和已记录查询到用户、身份验证、团队和服务帐户:

图 3.10 – 管理面板
现在我们已经探索了 Grafana Cloud 门户,接下来让我们准备本地环境以发送数据。
安装前提工具
Grafana 与数据结合时更加精彩!为了构建一个真实的 Grafana 工作原理视图,并帮助您的组织,我们选择安装 OpenTelemetry 演示应用程序。这是一个销售望远镜和其他观测设备的演示网店。我们将带您完成安装过程,帮助您在本地计算机上运行该应用程序。
但首先,您的本地环境需要具备一些前提条件,这些条件取决于您使用的操作系统。
在本节中,我们将解释如何安装以下内容:
-
基于您的操作系统的工具:
-
Windows 子系统 Linux 版本 2 (WSL2)
-
macOS Homebrew
-
-
Docker 或 Podman
-
单节点 Kubernetes 集群
-
Helm
安装 WSL2
WSL 是一种直接在 Windows 上运行 Linux 文件系统和工具的方式。它用于在不同操作系统之间提供一套标准的命令和工具。虽然也可以在 WSL 外运行这些系统,但使用 WSL 会简化许多流程。请按照以下步骤设置 WSL2:
-
以管理员身份打开 PowerShell 终端或 Windows 命令提示符。
-
运行以下命令以安装 WSL2:
C:\Users\OwG> wsl --install这将安装 Ubuntu 版本的 Linux。
你应该看到一个信息,表示 Ubuntu 正在安装,随后会提示输入新的 UNIX 用户名。如果看到任何其他信息,可能你已经安装了某个版本的 WSL;请参考微软官网解决这个问题。
-
为你的 Ubuntu 安装创建一个新的用户,输入用户名和密码。这个用户名和密码无需与 Windows 的用户名和密码相匹配。
-
通过运行以下命令来升级软件包:
sudo apt update && sudo apt upgrade推荐安装 Windows Terminal 来使用 WSL。你可以从微软商店下载: https://learn.microsoft.com/en-us/windows/terminal/install。
更详细的安装说明以及如何解决可能出现的任何问题,请参考 learn.microsoft.com/en-us/windows/wsl/install。
安装 Homebrew
Homebrew 是 macOS 的一个包管理工具。要在系统上安装它,请按照以下步骤操作:
-
打开终端窗口。
-
运行以下命令安装 Homebrew:
wget (used later in the setup process):$ brew install wget
该安装的详细说明可以在 brew.sh/ 找到。
安装容器编排工具
Docker 和 Podman 都是 容器编排工具。Docker 已经是事实上的标准约十年。Podman 是一个较新的工具,首次发布于 2018 年。Docker 的主要功能也在 Podman 中提供,但支持和信息可能更难找到。
在 2021 年,Docker 做出了许可更改,这些更改在 2023 年 1 月正式生效。这些许可更改可能会影响使用企业设备的读者。我们将只提供 Docker 的安装说明,但我们会指出潜在的问题,以便你了解。提供容器编排工具的目的是在该工具上运行单节点 Kubernetes 集群。
安装 Docker Desktop
以下部分简要描述了如何在 Windows、macOS 和 Linux 上安装 Docker Desktop。我们首先来看一下 Windows 安装过程。
Windows 安装
要在 Windows 上安装 Docker Desktop,请执行以下操作:
-
访问
docs.docker.com/desktop/install/windows-install/并下载最新的 Docker 安装程序.``exe文件。 -
运行安装包。系统会提示你启用 WSL2,选择 是。
-
安装完成后,启动 Docker Desktop。
-
导航到 设置 | 常规。勾选 使用基于 WSL2 的 引擎 复选框。
-
选择 应用并 重启。
-
在你的 WSL 终端中,通过运行以下命令验证 Docker 安装:
$ docker --version Docker version 20.10.24, build 297e128
macOS 安装
对于 macOS 上的 Docker Desktop 安装,请执行以下操作:
-
访问
docs.docker.com/desktop/install/mac-install/并下载适用于你 Mac 的最新 Docker 安装程序。 -
运行安装包。
-
在你的终端中,通过运行以下命令验证 Docker 安装:
$ docker --version Docker version 20.10.24, build 297e128
Linux 安装
Linux 用户可以考虑使用 Podman Desktop,因为它对 Linux 环境有更好的原生支持。安装说明可以在 podman-desktop.io/docs/Installation/linux-install 找到。
然而,如果你确实希望使用 Docker,请按照提供的安装指南操作,因为安装过程会因发行版而有所不同:https://docs.docker.com/desktop/install/linux-install/。
完整的文档可以在 https://docs.docker.com/desktop/ 找到。
在一个支持容器化的基础系统上,让我们设置一个单节点 Kubernetes 集群。这将用于轻松且可重复地安装 OpenTelemetry 示例应用程序。
安装单节点 Kubernetes 集群
有几种不同的工具可以运行本地 Kubernetes 集群,包括Kubernetes in Docker(KinD)、Minikube和MicroK8s。然而,我们选择使用k3d,因为它在不同操作系统上的安装非常简便。请按照以下步骤操作:
-
使用以下命令安装 k3d:
$ wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash完整的详情请参见
k3d.io/stable/。 -
创建一个 k3d 集群:
$ k3d cluster create owg-otel-demo -
验证集群状态:
$ kubectl get nodes NAME STATUS ROLES AGE VERSION k3d-owg-otel-demo-server-0 Ready control-plane,master 13d v1.25.7+k3s1
安装了 Kubernetes 集群后,我们现在需要一种便捷的方式来安装应用程序。OpenTelemetry 提供了 Helm 图表,允许我们将应用程序部署到 Kubernetes 上;我们将安装 Helm 来使用这些图表。
安装 Helm
Helm 是 Kubernetes 集群的包管理器。许多基础设施级别的组件都以 Helm 图表形式提供以供安装,OpenTelemetry 也不例外。要安装 Helm,请按照以下步骤操作:
-
使用以下命令安装 Helm(详细信息请参见
helm.sh/docs/intro/install/):$ wget –q –O - https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash -
验证 Helm 安装:
$ helm version version.BuildInfo{Version:"v3.11.3", GitCommit:"323249351482b3bbfc9f5004f65d400aa70f9ae7", GitTreeState:"clean", GoVersion:"go1.20.3"}
当我们的本地系统已经准备好运行应用程序时,我们可以安装 OpenTelemetry 提供的示例应用程序。
安装 OpenTelemetry 示例应用程序
由于我们需要将数据从本地机器发送到 Grafana Cloud 实例,我们需要提供一些凭据,并告诉本地机器将数据发送到哪里。在安装示例应用程序之前,我们需要设置访问令牌,以便将数据发送到我们的 Grafana Cloud 堆栈。
设置访问凭据
访问令牌允许 OpenTelemetry 应用程序将数据安全地发送到你的 Grafana Cloud 堆栈。要设置访问令牌,我们需要执行以下步骤:
-
在 Grafana Cloud 门户中,选择Security部分中的Access Policies。
-
点击Create access policy。
-
选择一个名称和显示名称,并将Realm设置为All Stacks。
-
设置Write范围,用于指标、日志和跟踪,然后点击Create。
-
在新的访问策略中,点击Add token。
-
给令牌命名并设置过期日期。点击Create。
-
最后,复制令牌并安全保存。
现在我们已经创建了令牌,接下来让我们下载本书的 GitHub 仓库并进行设置。
下载仓库并添加凭证和端点。
Git 仓库包含每一章节使用实时数据的配置文件。下载这个仓库很简单。访问 Git 仓库:github.com/PacktPublishing/Observability-with-Grafana。点击绿色的 代码 按钮,并按照提示克隆仓库。下载后,仓库应该像这样:

图 3.11 – 使用 Grafana 的可观测性仓库
为了设置演示应用,我们需要将之前保存的令牌和正确的端点添加到 OTEL-Creds.yaml 文件中。你需要的信息如下:
-
密码:这是你之前保存的令牌,每种遥测类型共享此令牌。
-
用户名:这对于每种遥测类型是特定的。
-
端点:这对于每种遥测类型是特定的。
以 Loki 为例,以下是在 Grafana Cloud Portal 中获取正确信息的步骤:
- 点击 Loki 框中的 发送日志 按钮。页面顶部有一个信息框,样式如下:

图 3.12 – Grafana 数据源设置
-
用户 字段用于输入用户名。
-
将
/loki/api/v1/push添加到 URL 的末尾。 -
对于指标,在 URL 末尾添加
/api/prom/push。 -
对于追踪信息,去掉
https://并在 URL 末尾添加:443。 -
将这些信息添加到
OTEL-Creds.yaml文件中相应的字段。
Loki 配置完成后,我们可以按照相同的过程配置 Prometheus(点击 发送指标)和 Tempo(点击 发送追踪)。
这些步骤在仓库中的 README.md 文件中有重复并扩展。凭证保存后,我们现在准备部署 OpenTelemetry。
安装 OpenTelemetry 收集器。
更新凭证文件后,我们可以安装 OpenTelemetry 收集器的 Helm 图表。这是收集和传输演示应用产生的数据的组件。继续安装的步骤如下:
-
添加 OpenTelemetry 仓库:
$ helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts -
使用 Helm 安装收集器:
$ helm install --version '0.73.1' --values chapter3/OTEL-Collector.yaml --values OTEL-Creds.yaml owg open-telemetry/opentelemetry-collector NAME: owg-otel-collector LAST DEPLOYED: Sun May 14 13:53:16 2023 NAMESPACE: default STATUS: deployed REVISION: 1 … -
验证安装是否成功:
$ kubectl get pods NAME READY STATUS RESTARTS AGE owg-otel-collector-opentelemetry-collector-6b8fdddc9d-4tsj5 1/1 Running 0 2s
我们现在准备安装 OpenTelemetry 演示应用。
安装 OpenTelemetry 演示应用。
OpenTelemetry 演示应用是一个示例网店,出售望远镜及其他观测宇宙的工具。要安装此演示应用,按照以下步骤操作:
-
使用 Helm 安装演示应用:
$ helm install --version '0.26.0' --values owg-demo open-telemetry/opentelemetry-demo NAME: owg-otel-demo LAST DEPLOYED: Mon May 15 21:58:37 2023 NAMESPACE: default STATUS: deployed REVISION: 1 … -
验证安装是否成功。首次安装此过程可能需要几分钟:
frontendproxy access:$ kubectl port-forward svc/owg-demo-frontendproxy 8080:8080 &
-
为浏览器跨度打开端口:
$ kubectl port-forward svc/owg-opentelemetry-collector 4318:4318 & -
请检查是否可以访问 OpenTelemetry 演示应用程序:http://localhost:8080:

图 3.13 – OpenTelemetry 演示应用程序
- 探索 OpenTelemetry 演示应用程序以生成一些数据。花些时间将物品添加到购物车并进行购买。虽然负载生成器是安装的一部分,但熟悉该应用程序还是很有价值,因为它有助于将生成的遥测数据放在上下文中进行分析。
现在你有了一个能生成数据的应用程序,让我们开始探索这些数据。
探索来自演示应用程序的遥测数据
假设安装成功,你的数据将流入你的 Grafana 实例。要查看这些数据,请前往你的 Grafana 实例,无论是通过你的团队 URL 还是点击 Cloud Portal 中的启动按钮。
在首页,你应该看到详细的关于当前或可计费使用情况的日志、指标和追踪信息。如果一切正常,这些值应该都大于 0。可能需要几分钟时间才能完全显示出来,有时可能需要一个小时:

图 3.14 – Grafana Cloud 使用情况
重要说明
如果你没有看到指标、日志和追踪的使用情况,可能需要进行故障排除。我们在本章末尾提供了一些提示。
点击菜单并选择探索。这将带你进入一个页面,在那里你可以对来自演示应用程序的遥测数据进行查询。在 Grafana 中,最高级别的概念是数据源。这些可以在主菜单下方选择。每个数据源都是 Grafana 实例与 Grafana Stack 中的一个组件或其他工具之间的连接。每个数据源都是自包含的。数据源菜单可以在下图中看到:

图 3.15 – 数据源菜单
你将看到有数据源用于日志、prom(Prometheus 指标)和追踪。还有其他数据源,但本章我们只关注这三种,因为它们是与我们已配置的 Grafana Stack 相关的数据源。
这些数据源与我们的 Loki、Mimir 和 Tempo 组件相关,分别用于收集日志、指标和追踪。我们接下来会讨论这些内容。
Loki 中的日志
Loki 存储了演示应用程序生成的日志数据。让我们快速看一下 Loki 数据源的界面,看看演示应用程序生成的一些日志数据。
选择 grafanacloud-<team name>-logs 数据源。在标签过滤器中,添加 exporter = OTLP 并点击 运行查询。现在你应该看到一个类似这样的界面:

图 3.16 – 审查日志
屏幕的上方区域是您输入和修改查询的地方。在屏幕中间,您将看到通过搜索返回的日志量随时间的变化。这可以一眼提供大量上下文信息。屏幕的下部显示您的查询结果:

图 3.17 查询面板详情
让我们将前面的截图分解成各个组件:
-
您可以选择时间范围并通过点击添加将查询添加到各种工具中。
-
使用本节底部的按钮,您可以通过添加查询进行更复杂的数据分析。查询历史让您查看查询历史。查询检查器帮助您了解查询的执行情况。
-
构建器或代码选择器允许您在默认显示的以 UI 为中心的查询构建器和查询语言输入框之间切换,这对于直接输入查询非常有用。
-
启动您的查询按钮将为您提供一些初始查询,标签浏览器按钮将让您浏览当前在收集的日志数据中可用的标签。
-
最后,解释查询滑块将为您提供有关当前查询每个步骤的详细解释。
让我们来看看查询结果面板中的组件:

图 3.18 – 查询结果面板详情
这些组件可以按如下方式使用:
-
您可以自定义数据显示时间戳,突出显示任何独特的标签,换行或美化 JSON。
-
您还可以应用去重。
-
您可以选择先查看最旧或最新的日志事件。
-
最后,您可以将数据下载为
.txt或.json格式。
我们将在第四章中更深入地探讨这些功能,并介绍 LogQL 查询语言。
现在您已经熟悉了 Loki 数据源中的日志查询面板,让我们看看从 Mimir 数据源查询度量数据是如何相似的。
Prometheus/Mimir 中的度量数据
Grafana 使用类似的重复块来查询数据。在本节中,我们将探讨如何查询度量数据。
选择grafanacloud-<团队名称>-prom数据源。在度量下拉框中选择kafka_consumer_commit_rate,并将标签过滤器留空。点击运行查询,您应该会看到像这样的屏幕:

图 3.19 – Kafka 消费者提交速率
类似于 Loki,我们在顶部有一个查询部分,尽管结构略有不同。主要的区别在于 选项 部分,它控制数据的展示方式。图例 管理图表的图例显示。格式 选项允许你选择 时间序列 表示(如前面截图中显示的图表);表格 表示,显示每个时间序列的每个值;以及 热图 表示。类型 选择器允许你选择时间范围、每个时间序列的最新时刻或两者。示例 滑块将显示与每个度量相关联的追踪数据。
底部部分显示了数据,并提供了以不同方式展示数据的选项。
要查看 Grafana 如何表示多个图表,从 Metric 下拉菜单中选择 process_runtime_jvm_cpu_utilization_ratio,然后点击 运行查询。你应该会看到一个像这样的图表:

图 3.20 – JVM CPU 使用率
前面截图中绘制的每一条线都代表了演示应用中不同服务的 CPU 使用率。我们将在第五章中更深入地探讨这些功能,并介绍 PromQL 查询语言。
Tempo 追踪数据源非常类似于 Loki 日志数据源和 Mimir 度量数据源。现在让我们来看一下。
Tempo 中的追踪
追踪需要更多的查询操作,因为我们必须找到并选择一个单独的追踪记录,然后详细展示该追踪中的跨度。
选择 grafanacloud-

图 3.21 – 选择一个追踪
点击一个 Trace ID 链接,你会看到像这样的屏幕:

图 3.22 – 追踪视图
这个视图展示了 Grafana 提供的分屏视图。可以从任何数据源访问此视图,并提供通过链接的数据点在日志、度量和追踪之间切换的能力,以便查看每种遥测类型中相同时间点或事件。如果你选择面板之间的条形,如前面截图中所示的数字 1,可以通过点击并拖动来放大追踪视图。
查看追踪记录时,每一行代表一个跨度,显示了涉及的服务以及该服务的具体信息。例如,checkoutservice 会显示购物车中的商品数量和运费。每个跨度上的条形显示了该跨度所用的总时间,并以堆叠的方式表示跨度的相对开始和结束时间。你可能会看到 productcatalogueservice 在交易中占用了大量时间,如图 3.21所示。
添加你自己的应用程序
你可以将自己的应用程序添加到此演示安装中。OpenTelemetry Collector 已经部署,接收器可用于 OTLP 格式的数据,gRPC 数据使用端口4317,HTTP(s)数据使用端口4318。要部署你的应用程序,需要将其打包为容器,并按照 Kubernetes 的标准部署机制进行部署。请注意,k3d 有自己的约定,默认使用 Flannel 进行网络配置,使用 Traefik 进行入口控制。
现在我们已经了解了这个演示应用程序,让我们来看一些排查问题的技巧,这些技巧会帮助你在设置或使用时遇到问题时解决它们。
排查你的 OpenTelemetry 演示安装问题
在使用此应用程序时可能会发生各种问题,因此本节内容未必涵盖所有情况。我们假设所有先决条件工具已正确安装。
让我们首先看看 Grafana 凭证的正确格式。
检查 Grafana 凭证
如果 OpenTelemetry Collector 出现身份验证错误,或者未收到数据,可能是凭证格式不正确。这些详细信息需要从本书的 Git 仓库中的OTEL-Creds.yaml文件中输入。
Grafana 凭证应按照以下格式:
-
用户名:数字,通常为六位数字。
-
密码:API 令牌,这是一个由字母和数字组成的长字符串。在排查令牌问题时有一些重要的注意事项:
-
相同的令牌可以被所有导出器共享。
-
与 API 令牌关联的访问策略需要具备写入日志、指标和追踪的权限。可以在 Grafana Cloud 门户中检查这一点。
-
-
loki:https://logs-prod-006.grafana.net/loki/api/v1/push -
prometheusremotewrite:https://prometheus-prod-13-prod-us-east-0.grafana.net/api/prom/push -
otlp(tempo):tempo-prod-04-prod-us-east-0.grafana.net:443
重要提示
Tempo 的 OTLP 端点与其他端点不同。
如果你发现自己犯了错误,需要使用helm upgrade将对OTEL-Creds.yaml文件所做的更改部署到系统中:
helm uninstall and then use the original instructions to reinstall.
The most common problem is with the access credentials, but sometimes you will need to look at the collector logs to understand what is happening. Let’s see how to do this now.
Reading logs from the OpenTelemetry Collector
The next place to investigate is the logs from the OpenTelemetry Collector.
Kubernetes allows you to directly read the logs from a Pod. To do this, you need the full Pod name, which you can get using the following command:
$ kubectl get pods --selector=app.kubernetes.io/instance=owg
名称 就绪 状态 重启次数 运行时间
owg-opentelemetry-collector-567579558c-std2x 1/1 正在运行 0 6 小时 26 分钟
In this case, the full Pod name is `owg-opentelemetry-collector-567579558c-std2x`.
To read the logs, run the following command:
$ kubectl logs owg-opentelemetry-collector-567579558c-std2x
Look for any warning or error-level events, which should give an indication of the issue that is occurring.
Sometimes, the default logging does not give enough information. Let’s see how we can increase the logging level.
Debugging logs from the OpenTelemetry Collector
If the standard logs are not enough to resolve the problem, the OpenTelemetry Collector allows you to switch on **debug logging**. This is typically verbose, but it is very helpful in understanding the problem.
At the end of `OTEL-Creds.yaml`, we have included a section to manage the debug exporter. The verbosity can be set to `detailed`, `normal`, or `basic`.
For most use cases, switching to `normal` will offer enough information, but if this does not help you to address the problem, switch to `detailed`. Once this option is changed, you will need to redeploy the Helm chart:
$ helm upgrade owg open-telemetry/opentelemetry-collector -f OTEL-Collector.yaml
This will restart the Pod, so you will need to get the new Pod ID. With that new ID, you can look at the logs; as we saw in the previous section, you should have a lot more detail.
Summary
In this chapter, we have seen how to set up a Grafana Cloud account and the main screens available in the portal. We set up our local machine to run the OpenTelemetry demo application and installed the components for this. Finally, we looked a the data produced by the demo application in our Grafana Cloud account. This chapter has helped you set up an application that will produce data that is visible in your Grafana Cloud instance, so you can explore the more detailed concepts introduced later with real examples.
In the next chapter, we will begin to look in depth at logs and Loki, explaining how best to categorize data to give you great insights.
第二部分:在 Grafana 中实现遥测
本部分将带你了解不同的遥测来源,解释它们是什么、何时使用它们,以及需要注意的问题。你将查看与主要云服务提供商的集成:AWS、Azure 和 Google。本部分还将探讨使用 Faro 进行的真实用户监控、使用 Pyroscope 进行的性能分析,以及使用 k6 进行的性能测试。
本部分包含以下章节:
-
第四章,使用 Grafana Loki 查看日志
-
第五章,使用 Grafana Mimir 和 Prometheus 进行指标监控
-
第六章,使用 Grafana Tempo 跟踪技术细节
-
第七章,使用 Kubernetes、AWS、GCP 和 Azure 进行基础设施查询
第四章:使用 Grafana Loki 查看日志
在本章中,我们将亲身体验 Grafana Loki。我们将学习如何使用 LogQL,这是用于查询 Loki 的语言,如何选择和过滤日志流,以及如何使用可用的操作符和聚合。这将为你提供适当提取数据以用于仪表板可视化和警报的工具。我们还将回顾日志格式的优缺点以及它如何影响你对 Loki 的使用。为了充分探索 Loki 的优势,我们将探索其架构及其在性能上的扩展性。最后,我们将探讨 LogQL 的高级内容,例如标签和转换,以及其他技巧和窍门,以扩展你对 Loki 的使用。
本章将涵盖以下主要内容:
-
介绍 Loki
-
理解 LogQL
-
探索 Loki 的架构
-
提示、技巧和最佳实践
技术要求
在本章中,你将使用 Grafana Cloud 实例以及你在 第三章 中设置的演示来操作 LogQL。LogQL 的完整语言文档可以在 Grafana 网站的 grafana.com/docs/loki/latest/logql/ 上找到。Loki 正在积极开发中,因此值得频繁检查新功能。
你可以在 GitHub 仓库的 github.com/PacktPublishing/Observability-with-Grafana/tree/main/chapter4 找到本章的代码。在 packt.link/aB4mP 上,你可以找到本章的 Code in Action 视频。
更新 OpenTelemetry 演示应用程序
首先,让我们改进我们演示应用程序的日志记录。对于本章,我们在 GitHub 仓库的 chapter4 文件夹中提供了更新版的 OTEL-Collector.yaml 文件,其中包含了额外的 Loki 日志标签。这些说明假设你已经完成了 第三章 的演示项目设置。关于此过程的完整细节可以在 GitHub 仓库的 README.md 文件的 第四章 部分找到。
要升级 OpenTelemetry Collector,请按照以下步骤操作:
-
使用 Helm 升级采集器:
$ helm upgrade --version '0.73.1' --values chapter4/OTEL-Collector.yaml --values OTEL-Creds.yaml owg open-telemetry/opentelemetry-collector NAME: owg-otel-collector LAST DEPLOYED: Sun Apr 25 12:15:03 2023 NAMESPACE: default STATUS: deployed REVISION: 2 … -
你可以通过以下命令验证升级是否成功:
$ kubectl get pods --selector=app.kubernetes.io/instance=owg NAME READY STATUS RESTARTS AGE owg-opentelemetry-collector-594fddd656-tfstk 1/1 Terminating 1 (70s ago) 2m8s owg-opentelemetry-collector-7955d689c4-gsvqm 1/1 Running 0 3s
现在,你将可以为 Loki 日志数据提供更多标签。接下来让我们探索一下这意味着什么。
介绍 Loki
Grafana Loki 从一开始就被设计为一个高度可扩展的多租户日志解决方案。它的设计深受 Prometheus 的影响,具有以下几个主要目标:
-
它是为开发者和运维人员设计的(例如在 第一章 中介绍的 Diego 和 Ophelia)
-
它具有简单的摄取过程;不需要预处理
-
它仅索引关于日志的元数据
-
它将所有内容存储在对象存储中
让我们来看一下 Loki 如何获取数据并使用标签,因为这将为你提供宝贵的见解,帮助你理解查询如何获取和处理数据以进行展示:
-
日志获取:Loki 接受来自所有来源的日志,提供了多种代理选项,简化了这一过程。你甚至可以直接将日志数据发送到 Loki API。这使得它成为复杂环境中包含众多系统和硬件组件的理想选择。
Loki 将其日志存储为日志流,每个条目都有以下内容:
-
时间戳:它具有纳秒级精度,确保准确性。
-
标签:这些是用于识别和检索数据的键值对;它们构成了 Loki 的索引。
-
内容:指的是原始日志行。它没有被索引,而是以压缩块的形式存储。
以下图示展示了一个日志流及其日志行和相关元数据:
-

图 4.1 – Loki 日志结构
-
日志标签:Loki 日志标签提供日志行的元数据,不仅有助于识别数据,还用于创建日志流的索引并构建日志存储结构。它们具有以下特点:
-
每一组唯一的标签和值都会创建一个日志流
-
流中的日志被批量处理、压缩并存储为块
-
标签是 Loki 日志流的索引
-
标签用于搜索日志
-
以下图示展示了两个日志流。正如你所见,在一个日志流中,每条日志都有相同的唯一标签集。在这个例子中,k8s_node_name有两个值:

图 4.2 – Loki 日志流
现在我们已经了解了 Loki 日志的结构,接下来让我们介绍LogQL,这是用于从日志中提取价值的查询语言。
理解 LogQL
Grafana 开发了 LogQL 作为 Loki 的查询语言,并以Prometheus 查询语言(PromQL)为灵感。它的设计考虑了开发人员(Diego)和运维人员(Ophelia)(你可以参考第一章了解这些人物角色),提供了熟悉的过滤和聚合机制。Loki 不会对日志内容进行索引。日志事件被分组为日志流,并通过标签(日志元数据)进行索引。在 Loki 中执行 LogQL 查询时,会对日志流进行一种分布式过滤,以聚合日志数据。
让我们探索用于 LogQL 的Grafana Explorer UI,你将在这里执行大多数 LogQL 查询。
LogQL 查询构建器
我们在第三章的图 3.16中简要查看了 Grafana Explorer UI。对于我们的示例,我们将主要在代码编辑器中使用原始的 LogQL。以下截图显示了直接在查询构建器代码编辑器中输入的 LogQL:

图 4.3 – LogQL 查询构建器代码编辑器
如果你在 LogQL 使用过程中遇到困难,可以依赖 日志查询起始点 和 解释查询 工具来帮助你入门,理解每个管道步骤的作用。
日志查询起始点提供了一些快速示例,帮助你轻松开始过滤和格式化数据:

图 4.4 – 日志查询起始点
同样,度量查询起始点提供了一些快速示例,帮助你与数据进行交互,并生成可在仪表板和警报中使用的度量值:

图 4.5 – 度量查询起始点
可在 LogQL 查询构建器和仪表板面板编辑器中使用,解释查询功能在启用时提供 LogQL 管道各阶段的详细分解。这个工具在分析现有查询或调试自己设计的查询时非常有用:

图 4.6 – 解释查询
现在让我们来探索 LogQL 中可用于选择、过滤和解析日志数据的功能。
LogQL 功能概述
一个基本的 LogQL 查询由一个或多个日志流选择器组成,用于检索原始日志块进行处理,还可以选择使用日志管道过滤和解析日志数据。以下图展示了一个基本的 LogQL 查询,使用了 component="cartservice" 选择器和管道过滤器,|= `GetCartAsync`, 这将返回来自 图 4.2 中日志流示例的两行:

图 4.7 – 一个基本的 LogQL 查询
下表展示了在构建 LogQL 查询时可用的不同功能,帮助你熟悉使用 Loki 查询日志:
| LogQL 部分 | 语法 | 运算符 | 范围 |
|---|---|---|---|
| 流选择器 | {``label="value", foo!="bar"} |
=,!=,=~,!~ |
选择要检索的日志流;必须始终至少有一个选择器 |
| 行过滤器 | |= ` ```` error` |
|=,!=,|~,!~ |
Filter to matching log lines |
| Parser | | json |
json, logfmt, pattern, regexp, unpack |
Parse and extract labels from the log content, with parses for structured and unstructured logs |
| Label filter | | label="value" |
=,!=,=~,!~,<,<=,>,>= |
Filter log lines using original and newly extracted labels |
| Line format | | line_format "{{.label}}" |
Rewrite the log line content for presentation purposes | |
| Label format | | new_label="{{.label}}" |
Rename, modify, or add labels |
Table 4.1 – LogQL feature overview
Let’s start by looking at the log stream selector in detail.
Log stream selector
Selecting log streams to include in your query results requires filtering based on the Loki labels using simple operators. By improving the granularity of your log stream selector, you can reduce the number of streams searched and improve query performance. We will discuss this in more detail later in this chapter when we look at the Loki architecture. There must always be at least one stream selector, but it must be written in a way that will not match empty values; for example, the {label=~".*"} will fail as a 0 or more quantifier and {label=~".+"} will pass as a 1 or more quantifier. Multiple stream selectors can be used and are separated using commas. The log stream selector must be the first item in your LogQL query and identified with curly braces. For example, the following LogQL query will select log streams where the component label ends with service and the name label equals owg-demo-checkoutservice:
{component=~".+service", name="owg-demo-checkoutservice"}
As mentioned at the beginning of this section, LogQL was inspired by PromQL and as such, the Prometheus label selector rules have been adopted by LogQL for log stream selectors:
| Operator | Meaning |
| = | Exactly equal |
| != | Not equal |
| =~ | Regex matches |
| !~ | Regex does not match |
Table 4.2 – Log stream selector operators
Grafana has implemented the Golang RE2 syntax for log streams, which means you will have to match against entire strings. This includes newlines, so it’s worth checking this if your regex filters are failing. Syntax documentation can be found here: github.com/google/re2/wiki/Syntax.
Once you have your log streams selected, the log pipeline can then be used to filter and process them. Let’s discuss this next.
Log pipeline
As we presented in Table 4.1, the expressions available are line and label filters, parsers, and formatters. Expressions are executed in sequence for each line of the log stream, dropping anything filtered out and moving on to the next line.
Expressions allow you to transform or mutate the log data to then use it for additional filtering/processing. Let’s look at the following example (this is the pipeline section only; you would need the {component=~".+service"} selector to make it work in Grafana):
|= `emailservice`
| json
| resources_k8s_container_restart_count > 0
| line_format `{{.body}}`
| __error__=``
Here, we’re doing the following tasks:
- We start by matching the logs containing
emailservice. - We then use the
jsonparser to extract additional labels that are filtered whereresources_k8s_container_restart_countis greater than 0. - We then rewrite the log line to only contain the contents of
body. - Finally, we strip all formatting and parsing errors.
Let’s now look at each of the log pipeline expressions and how to use them.
Line filters
Grafana describes grep over the aggregated logs from the matching log streams. We will understand this statement better in the Loki’s architecture section. For now, it’s fine to just understand line filters as case-sensitive searches through log line contents dropping lines that do not match. Filter expressions are made up of a filter operator followed by text or regex. The following table shows the meaning of each expression with examples:
| Operator | Meaning | Example |
| |= | Log line contains a string | |= ` ```` emailservice` |
| != | 日志行不包含某个字符串 | != ` ```` emailservice` |
| |~ | Log line contains a match to the regex | |~ ` ```` email\w+` |
| !~ | 日志行不包含与正则表达式匹配的内容 | !~ ` ```` email\w+` |
Table 4.3 – Line filters
It is best practice to start log pipelines with line filter expressions to reduce the result set for subsequent expressions and improve the performance of the query.
IP address matching
LogQL provides a useful function to aid ip("<pattern>") syntax, it supports both IPv4 and IPv6 addresses, address ranges, and CIDR patterns. This function works for both line and label filters with a slight caveat in implementation; only |= and != are allowed for line filter expressions. We’ll look at this in the context of label filters later in this section.
The following examples show various patterns (ip(<pattern>)) along with an explanation of what each will do, for both IPv4 and IPv6:
ip("192.168.0.22")andip("::1")ip("192.168.0.1-192.189.10.12")andip("2001:db8::1-2001:db8::8")ip("192.52.100.0/24")andip("2001:db8::/32")
Decolorize
In Chapter 2, we mentioned unstructured logging is often color-coded to improve readability on the computer terminal. However, in a log aggregation system, such as Loki, those color codes are displayed in full. For example, the color red would be displayed as \u001b31m.
Loki has a simple line filter expression that removes these ANSI sequences for color codes so that you can clean the log to make it more readable in Grafana:
{name="emailservice"} | decolorize
Parsers
We have said this before: Loki accepts logs from all sources. It does not really matter what your logs look like; they can come in structured, semi-structured, or unstructured formats. It is, however, important when designing and building observability solutions to understand the log formats you are working with. This ensures that you can ingest, store, and parse log data in a way it can be used effectively. The personas in [Chapter 1 give you an idea of who these will be used by and for what purpose.
Having a good understanding of your source log format is important to instruct you on what to use and help with your overall observability design. The following LogQL parsers can be used to parse and extract labels from your log content:
json: If your log content is structured or semi-structured JSON and has embedded JSON (which can be isolated using theline_formatexpression), the| jsonon its own will extract all of the JSON properties as labels. Any nested properties will be represented as a single label separated with_. Arrays are skipped completely when extracting all of the properties. Additionally, expressions can be passed into the JSON parser as quoted strings to restrict the output to only the labels required, for example,| json label1="expression", label2="expression", where the expression identifies a key or nested key. Arrays are returned where identified by expressions and they are assigned to the label formatted as JSON.logfmt: If your log content is structured, single-level key-value pairs, it can be parsed with the| logfmton its own will extract all of the key-value pairs. Similar to the JSON parser, expressions can be passed into thelogfmtparser as quoted strings to restrict the output to only the labels required, for example,| logfmt label1="expression", label2="expression", whereexpressionidentifies a key.pattern: For unstructured log content, the| pattern "<expression>", whereexpressionmatches the structure of a log line. The pattern parser expression is made up of captures delimited by the<and>characters and literals, which can be any sequence of UTF-8 characters.regexp: Unstructured log content can also be extracted using the| regexp "<expression>", whereexpressionis a regex pattern that complies with the Golang RE2 syntax. A valid expression must contain at least one sub-match, with each sub-match extracting a different label.unpack: If you are using a compatible logging agent, such as Grafana Agent or Promtail, you can take advantage of theunpackparser to unpack embedded labels created by Promtail’spackfeature. With Promtail’spackfeature, the original log line is stored in the_entrykey. This value will be used to replace the log line.
Label filters
We discussed log labels at the beginning of this section with regard to log ingestion and retrieval. Additionally, labels can be extracted as part of the log pipeline using parser and formatter expressions. The label filter expression can then be used to filter your log line with either of these labels.
The statement part of the filter is referred to as the predicate, and in the case of label filters, it contains the following:
- The label identifier
- The operation
- A value
For example, in name="emailservice", the name label is compared, using the = operator, with the value "emailservice". It is processed from left to right, so the label identifier must start the predicate.
Value types are inferred from your query input. In the following table, you will find an overview of these types as a useful reference for building your label filters:
| Value Type | Description |
| String | Can be surrounded with double quotes or backticks, for example, "emailservice" or `emailservice`. |
| Duration | Structured as a sequence of decimal numbers. They can optionally contain fractions and the unit can be declared as a suffix, for example, "280ms", "1.3h", or "2h30m". Units of time that can be used are "ns", "us" (or "µs"), "ms", "s", "m", and "h", and as the examples show, you can use multiple units: "2h30m". |
| Number | Standard floating-point numbers, for example, 357 or 98.421. |
| Bytes | Structured as a sequence of decimal numbers. They can optionally contain fractions and the unit can be declared as a suffix, for example, "36MB", "2.4Kib", or "18b". Units for bytes that can be used are "b", "kib", "kb", "mib", "mb", "gib", "gb", "tib", "tb", "pib", "pb", "eib", and "eb". |
Table 4.4 – Value types
Let’s now look at these value types in more detail:
-
=,!=,=~, and!~operations can be used. Thestringtype is used to filter the built in label__error__, which is often used to strip formatting and parsing errors from results; for example,|__error__=``. -
=or==Equals
!=Does not equal
>and>=Is greater than or greater than and equal to
<and<=Is less than or less than and equal to
Table 4.5 – Type operators
Take the example | resources_k8s_container_restart_count > 0. Loki attempts to convert the value for use with the operator if it needs to. If there are any errors with the conversion, the __error__ label will be added to the log line, which as we demonstrated earlier, can be filtered out using | __error__=``.
Grafana LogQL also allows for multiple predicates to be chained together using and and or . and can alternatively be expressed using , or | or <space>.
For example, all of the following produce the same output:
| quantity >= 2 and productId!~"OLJ.*"
| quantity >= 2 | productId!~"OLJ.*"
| quantity >= 2 , productId!~"OLJ.*"
| quantity >= 2 productId!~"OLJ.*"
We described = and != label matchers are allowed. Once you have filtered and parsed your logs as required, you can begin to transform the data, whether that is for presentation or further pipeline processing. We will discuss the two ways of doing this in detail next. But first, let’s explore template functions, which are implemented by both line and label filters.
Template functions
The Golang text/template format has a large set of available template functions, all of which are available for use in LogQL queries. Full documentation can be found on the Grafana website. The templating engine has access to your data in various ways:
- It can treat labels as variables, referencing them using
., for example,{{ .``component }} - It can access the log line itself using
__line__, for example,`{{ __line__ |lower }}` - It can access the log timestamp using
__timestamp__, for example,`{{ __timestamp__ | date " ```` 2023-04-25T12:15:03.00Z+01:00" }}`|
模板函数可以分为以下几个不同的领域:
-
正则表达式模式
-
字符串函数
-
数学函数
-
JSON 函数
-
日期和时间函数
此外,还有一些不一定适合归类的其他函数,但它们同样非常有用。包括编码和解码函数、字节和持续时间转换、计数以及默认值。
行和标签格式
有两个功能可用于转换日志:
-
| line_format "{{ .label }}"用于重写日志行内容。此表达式用于使用前面提到的模板函数修改日志行。LogQL 将所有标签作为变量注入到模板中,使它们可供使用,例如,| line_format "{{.label_one}} {{.label_two}}"。格式可以使用双引号或反引号,反引号可以避免转义字符。例如,如果我们有以下标签,
method=sent、status=200和duration=15ms,那么以下 LogQL 查询将返回sent200 15ms:{instance="owg-demo", component="featureflagservice"} |= `Sent` | json | regexp "(?P<method>Sent) (?P<status>\\d+?) in\\s(?P<duration>.*?ms)" |label_format new_label="{{ .label }}" is used to rename, modify, or even create new labels. It accepts a comma-separated list of equality operations, allowing multiple operations to be carried out simultaneously.To rename a label with another label, the label identifiers must be on both sides of the operator; for example, `target=source` will put the contents of the `source` label into the `target` label and drop the `source` label.A label can be populated using the Golang text/template format and functions detailed previously (double quotes or backticks). For example, if we have the `user=diego` and `status=200` labels, the `|label_format target="{{.status}} {{.user}}"` pipeline would define the `target` label as `200 diego`.Templating can be used if you wish to preserve the original `source` label. In the example, `target=source` removed the `source` label. We can write this as `target="{{.source}}"`, which will put the contents of the `source` label into the `target` label while preserving the `source` label. If the target label does not already exist, a new label is created.
重要提示
每个表达式中只能使用一个标签名称;例如,| label_format foo=bar,foo="new" 会失败。所需的结果可以通过两个表达式实现,依次执行,如下所示:| label_format foo=bar | label_format foo="new"。
我们已经了解了标签格式如何为你提供创建、修改和重命名标签的选项。此外,我们还有 drop labels 命令来完全删除标签。现在让我们来探讨这个表达式。
删除标签
drop labels 表达式用于从管道中删除标签。例如,如果我们有 user=diego、status=200 和 duration=1000(ms) 标签,则 |drop user 管道将删除 user 标签,只留下 status 和 duration。
我们现在将进一步了解 LogQL 的更多功能,探索格式化器、度量查询以及执行 LogQL 的 UI —— Grafana Explorer,在这里可以为所有数据源构建查询。
探索 LogQL 度量查询
Loki 和 LogQL 最强大的功能之一是能够从日志中创建度量指标。通过 度量查询,你可以,例如,计算错误率或过去一小时内日志量最大的前 10 个日志来源。这使得它非常适合创建可视化或触发警报。
如果我们将度量查询与本节前面查看的解析器和格式化器结合使用,它们可以用来从日志行中的示例数据计算指标。例如,延迟或请求大小可以从日志数据中提取并用作指标。然后,这些指标将可用于聚合和生成新系列。
现在让我们来看一下可用的聚合操作,即 范围向量聚合 和 内建的 聚合操作符。
范围向量聚合
Prometheus 中的 范围向量 概念在 LogQL 中得以共享,其中样本的范围是日志或标签值的范围。我们将在 第五章 中更详细地讨论范围向量的概念。所选聚合应用于一个时间区间,该区间以数字后跟单位的形式指定。可以使用以下时间区间单位:
-
ms: 毫秒 -
s: 秒 -
m: 分钟 -
h: 小时 -
d: 天 -
w: 周 -
y: 年
示例包括 6h、1h30m、10m 和 20s。
Loki 和 LogQL 支持两种类型的范围向量聚合:日志范围聚合 和 解包范围聚合。我们来详细探讨一下这两者。
日志范围聚合
一个 [10ms],应用于该函数以在持续时间内聚合查询。持续时间可以放置在日志流选择器后面或日志管道的末尾。
这里是聚合函数:
| 聚合 | 描述 |
|---|---|
rate(range) |
将计算每秒的条目数。 |
count_over_time(range) |
将计算给定范围内每个日志流的条目数。 |
bytes_rate(range) |
用于检测日志数据量的变化。它会计算每个日志流每秒的字节数。 |
bytes_over_time(range) |
用于计算日志数据量。它会计算给定区间内每个日志流使用的字节数。 |
absent_over_time(range) |
用于在一段时间内没有时间序列和日志流时触发警报。如果传递的区间中有元素,它会返回一个空向量;如果区间中没有元素,它会返回一个包含值 1 的单一元素向量。 |
表 4.6 – 日志范围聚合函数
这里是一些日志范围聚合的示例:
-
要计算过去 10 分钟内
currencyservice组件的所有日志行数:count_over_time({component="currencyservice"}[10m]) -
在过去一分钟内按组件汇总每秒错误率:
sum by (component) (rate({component=~".+service"} |= "error" [1m]))
解包区间聚合
unwrap 函数用于提取值以便在聚合中使用。它们支持使用 by 或 without 子句进行分组,以便根据不同的标签进行聚合。without 聚合会从结果向量中删除标识的标签,同时保留所有其他标签。by 聚合会删除 by 子句中未标识的标签。
这里是聚合函数:
| 聚合 | 描述 |
|---|---|
rate(unwrapped-range) |
将计算区间内所有值的每秒总和的速率。 |
rate_counter( unwrapped-range) |
将计算区间内所有值的每秒速率,将它们视为计数器度量。 |
sum_over_time( unwrapped-range) |
将返回区间内所有值的总和。 |
avg_over_time( unwrapped-range) |
将返回区间内所有点的平均值。 |
max_over_time(range) |
将返回区间内所有点的最大值。 |
min_over_time( unwrapped-range) |
将返回区间内所有点的最小值。 |
first_over_time( unwrapped-range): |
将返回区间内所有点的第一个值。 |
last_over_time( unwrapped-range) |
将返回区间内所有点的最后一个值。 |
stdvar_over_time( unwrapped-range) |
将返回区间内值的总体标准差。 |
stddev_over_time( unwrapped-range) |
将返回区间内值的总体标准差。 |
quantile_over_time(scalar, unwrapped-range) |
将返回区间内指定分位数的值。 |
absent_over_time( unwrapped-range) |
当标签组合在一段时间内没有时间序列和日志流时,适用于告警。若传入的范围包含元素,则返回一个空向量;若传入的范围没有元素,则返回一个单元素向量,值为 1。 |
表 4.7 – 未封装范围聚合函数
sum_over_time、absent_over_time、rate 和 rate_counter 函数不参与分组。
这里是一些未封装范围聚合的示例:
-
计算
webserver容器中request_time的 99 百分位数,排除按path分类的 JSON 格式错误,并限制在过去的一分钟内:quantile_over_time(0.99, {container="webserver"} | json | __error__ = "" | unwrap duration_seconds(request_time) [1m]) by (path) -
计算过去一分钟内,
org_id处理的字节数,并筛选出日志中包含metrics字符串的记录:sum by (org_id) ( sum_over_time( {container="webserver"} |= "metrics" | logfmt | unwrap bytes(bytes_processed) [1m]) )
内置聚合运算符
LogQL 支持 PromQL 所支持的内置聚合运算符的子集。可以使用这些运算符对单一向量的元素进行聚合,得到一个新向量,包含更少的元素但具有聚合值。
下表展示了一些内置范围聚合运算符:
| 聚合 | 描述 |
|---|---|
sum |
将根据指定的标签计算总和 |
avg |
将根据指定的标签计算平均值 |
min |
将根据指定的标签选择最小值 |
max |
将根据指定的标签选择最大值 |
stddev |
将根据指定的标签计算总体标准差 |
stdvar |
将根据指定的标签计算总体标准方差 |
count |
将计算向量中元素的数量 |
topk |
将按样本值选择最大的 k 个元素 |
bottomk |
将按样本值选择最小的 k 个元素 |
sort |
将按样本值的升序返回向量元素 |
sort_desc |
将按样本值的降序返回向量元素 |
表 4.8 – 内置范围聚合函数
这里是一些内置范围聚合运算符的示例:
-
返回过去 10 分钟内按
name排名的前 10 个日志吞吐量最高的应用程序:topk(10, sum(rate({region="us-west1"}[10m])) by (name)) -
计算过去 10 秒内,各区域 Web 服务器日志中
/hello端点的GET请求的平均速率:avg(rate(({container="webserver"} |= "GET" | json | path="/hello")[10s])) by (region)
我们已经了解了 LogQL 如何解析不同的日志格式。现在让我们来看看 Loki 的架构,以及 Loki 如何存储和查询你发送的日志数据。
探索 Loki 的架构
Grafana Loki 具有完整的 微服务架构,可以作为一个单一二进制文件运行,并且可以简单地扩展部署为完整的微服务架构,将所有组件作为独立的进程运行。从高层次来看,它由实现写入、读取和存储功能的特性组成,如下图所示:

图 4.8 – Loki 架构的高级概览
写入 和 读取 功能可以独立扩展,以适应您的特定需求和使用案例。
在幕后,Loki 有以下核心组件:
-
分发器
-
Ingester
-
查询前端
-
查询器
-
后端服务:
-
规则引擎
-
压缩器
-
查询调度器
-
现在让我们更详细地了解一下功能和核心组件:
-
写入:接收日志数据的写入请求会先到达分发器,分发器负责数据分片和分区,并将其发送到 ingester。分发器验证每个流集,检查标签、时间戳和日志行大小,然后将日志流块批量发送到多个 ingester。
Ingester 写入 写前日志(WALs)以确保数据的可靠性,并最终写入对象存储后端。
查询器和规则引擎都会读取 ingester,以访问最新数据。查询器还可以访问对象存储中的数据。
-
读取:查询前端负责加速查询执行,将大型查询分发到多个查询器,并在失败时确保重试。
查询器解析 LogQL 并查询底层系统:ingester 获取最新数据,对象存储获取较旧数据。查询器通过去重相同纳秒时间戳、标签和日志内容的数据。
-
存储:对象存储是批量日志存储的地方。压缩器负责维护数据。它监控对象存储,进行数据去重并移除旧的日志。
-
后端服务:规则引擎评估查询并根据结果执行操作。操作可以是记录规则(为 LogQL 查询生成新指标)或系统事件的告警。
告警管理器负责系统中通知和告警的触发和发送,但这不包括在 Loki 中。
-
Loki 索引:在本章到目前为止,我们已经介绍了 Loki 日志标签和 LogQL 日志流选择器。底层架构完成了这幅图,解释了分发器如何对数据进行分片。正是这种分片和随后使用基于标签的 Loki 索引进行存储,使得 Loki 既快速又廉价。它还验证了良好的标签策略对于提升存储、检索和查询性能的重要性。
现在我们已经对 Loki 有了很好的理解,接下来让我们看看一些最佳实践和使用 Loki 日志数据的一些技巧。
提示、技巧和最佳实践
在本节中,我们将讨论一些过滤和基数的最佳实践。然后,我们将介绍 LogQL 分析器和 LogCLI,这些工具可以在你处理 Grafana Loki 日志数据时提供帮助。
以下是一些需要记住的最佳实践:
-
首先过滤:Loki 将原始日志以压缩块的形式存储在对象存储中。因此,从速度的角度来看,早期进行过滤是非常重要的。在较小的数据集上处理复杂的解析将增加响应时间。
-
namespace -
cluster -
job -
app -
instance -
filename
以下是一些不好的标签示例(通常含糊不清,且值的范围没有限制):
-
userid -
traceid -
path -
status code -
date
现在,让我们仔细看看使用 LogQL 分析器和 LogCLI 的优势:
- LogQL 分析器:LogQL 分析器提供了一个在 Grafana 网站上使用的界面,供你练习 LogQL 查询。你可以查看你的查询在一个示例日志条目上所执行操作的详细解释。请访问
grafana.com/docs/loki/latest/query/analyzer/进行尝试。让我们来看看 Loki LogQL 分析器:

图 4.9 – Loki LogQL 分析器
LogQL 分析器提供的解释比查询构建器中的Explain 查询功能更为详细,因此在学习 LogQL 时,值得一试。
-
使用 LogCLI:对于喜爱命令行的用户来说,Grafana Loki 提供了一个命令行接口 LogCLI,允许你在终端中执行以下操作:
-
查询你的日志
-
评估单一时间点的度量查询
-
识别 Loki 标签并获取其值的统计信息
-
返回带有标签匹配器的时间窗口日志流
-
如果你希望在不离开控制台的情况下访问 LogQL 的强大功能,这将是非常方便的。
完整的设置文档和命令参考可以在这里找到:grafana.com/docs/loki/latest/query/。你可以从 Loki 的 GitHub 发布页面下载二进制文件。
我们现在将总结本章内容,回顾你所学到的知识。
总结
在本章中,我们介绍了 Loki,探讨了日志摄取格式和日志标签的重要性。接着,我们开始研究 Loki 的查询语言 LogQL 的全面功能,以及如何选择日志流,然后过滤、解析、格式化和转换日志行。当你使用 Loki 构建仪表板时,这些技巧在第八章中将非常宝贵。然后,我们了解了 Loki 的架构,以便了解幕后发生的事情。我们还解释了数据是如何存储的,以及 Loki 如何通过扩展来提高性能。最后,我们回顾了一些可以帮助你提升 Loki 使用体验的技巧和最佳实践。
在下一章,我们将从日志转向探索度量和Prometheus,Loki 就是从这些地方汲取了最初的灵感。
第五章:使用 Grafana Mimir 和 Prometheus 进行指标监控
本章将介绍 Prometheus 查询语言(PromQL)。与 LogQL 类似,PromQL 可以用来选择和筛选指标流,并使用运算符和函数处理数值数据,使您能够构建快速高效的查询,从而支持建立可观察系统。我们还将探索并比较用于输出系统指标的各种协议。最后,我们将探索 Prometheus 和 Mimir 的架构,以了解 Mimir 如何满足高可扩展系统的需求。
本章将覆盖以下主要内容:
-
更新 OpenTelemetry 采集器以收集指标
-
介绍 PromQL
-
探索数据收集和指标协议
-
了解数据存储架构
-
在 Grafana 中使用示例数据
技术要求
本章中,您将需要以下内容:
-
在 第三章 中设置的 OpenTelemetry 演示应用程序
-
在 第三章 中设置的 Grafana Cloud 实例
-
Docker 和 Kubernetes
您可以在 GitHub 仓库中的 github.com/PacktPublishing/Observability-with-Grafana/tree/main/chapter5 找到本章的代码。您可以在 packt.link/A2g91 找到本章的 Code in Action 视频。
更新 OpenTelemetry 演示应用程序
对于本章,我们已经准备了更新版本的 OTEL-Collector.yaml 文件,该文件将为您添加更多的标签,以便您进一步探索。有关此过程的详细信息,请参阅 Git 仓库中的 README.md 文件。此过程将把新的采集器配置应用于您的演示应用程序:
-
使用 Helm,我们将更新的配置文件应用于我们的 Kubernetes 集群:
$ helm upgrade --version '0.73.1' --values chapter5/OTEL-Collector.yaml --values OTEL-Creds.yaml owg open-telemetry/opentelemetry-collector NAME: owg-otel-collector LAST DEPLOYED: Sun Mon 19 12:42:36 2023 NAMESPACE: default STATUS: deployed REVISION: 2 … -
验证升级是否成功:
$ kubectl get pods --selector=component=standalone-collector NAME READY STATUS RESTARTS AGE owg-otel-collector-594fddd656-tfstk 1/1 Terminating 1 (70s ago) 2m8s owg-otel-collector-7b7fb876bd-vxgwg 1/1 Running 0 3s
这个新配置增加了从 Kubernetes 集群和 OpenTelemetry 采集器收集指标的功能。该配置还做了一些必要的重新标记。
现在我们从本地演示应用程序收集更多的数据,让我们介绍用于查询这些数据的语言。
介绍 PromQL
Prometheus 最初由 SoundCloud 于 2012 年开发;该项目于 2016 年被 Cloud Native Computing Foundation 接受成为第二个孵化项目(继 Kubernetes 之后),并且很快发布了 1.0 版本。PromQL 是 Prometheus 的一个重要组成部分,用于查询存储的数据并生成仪表盘和警报。
在我们深入探讨语言的细节之前,让我们简要地看一下 Prometheus 兼容系统与指标数据交互的几种方式:
- 摄取度量:与 Prometheus 兼容的系统接受时间戳、键值标签和样本值。由于 Prometheus 时间序列数据库(TSDB)的细节相当复杂,下面的图示展示了度量的单个样本在摄取后如何存储的简化示例:

图 5.1 – 存储在 TSDB 中的度量数据简化视图
-
__name__值会创建一个app_frontend_requests。 -
每一组唯一的标签都会创建一个时间序列。在前面的图示中,所有标签的集合即为时间序列。
-
一个时间序列将包含多个样本,每个样本都有一个唯一的时间戳。前面的图示展示了一个单一的样本,但随着时间的推移,每个时间序列将会收集多个样本。
-
度量标签的唯一值数量被称为标签的基数。应避免使用基数较高的标签,因为它们会显著增加度量的存储成本。
下图展示了一个包含两个时间序列和五个样本的单一度量:

图 5.2 – 多个时间序列的样本示例
在 Grafana 中,我们可以查看度量的时间序列和样本的表现。为此,请按照以下步骤操作:
-
在你的 Grafana 实例中,选择菜单中的 Explore。
-
选择你的 Prometheus 数据源,标签为
grafanacloud-<team>-prom (default)。 -
在 Metric 下拉菜单中,选择 app_frontend_requests_total,在 Options 下,将 Format 设置为 Table,然后点击 Run query。这将显示选定时间范围内度量中的所有样本和时间序列。你应该看到如下数据:

图 5.3 – 可视化构成度量的样本和时间序列
现在我们已经了解了数据结构,接下来让我们探索 PromQL。
PromQL 功能概述
在本节中,我们将向你介绍 PromQL 的功能。我们将从数据类型的解释开始,然后我们将讨论如何选择数据、如何处理多个数据集以及如何使用函数。由于 PromQL 是一种查询语言,了解如何操作数据以生成警报和仪表板非常重要。
数据类型
PromQL 提供了三种数据类型,这些数据类型非常重要,因为 PromQL 中的函数和运算符会根据所呈现的数据类型有所不同:
- 瞬时向量是一种数据类型,用来存储包含单个样本的时间序列集合,这些样本共享相同的时间戳——也就是说,它表示在某一特定时刻的值:

图 5.4 – 一个瞬时向量
- 范围向量存储一组时间序列,每个时间序列包含具有不同时间戳的样本范围:

图 5.5 – 范围向量
- 标量是简单的数值,没有涉及标签或时间戳。
选择数据
PromQL 提供了多种工具,用于选择要在仪表盘或告警中显示的数据,或仅用于了解系统的状态。以下表格描述了其中的一些:
| 名称 | 语法 | 运算符 | 作用范围 |
|---|---|---|---|
| 度量选择器 | metric_name |
选择一个度量 | |
| 范围选择器 | [``5m] |
ms、s、m、h、d、w 和 y |
选择样本 |
| 标签选择器 | {``label="value", foo!="bar"} |
=、!=、=~ 和 !~ |
使用标签选择和过滤时间序列 |
| 偏移修饰符 | offset 5m |
ms、s、m、h、d、w 和 y |
将评估时间从当前时间点偏移指定的时间 |
@ 修饰符 |
@ 1686561123 |
@ |
将评估时间设置为特定时间,适用于瞬时或范围向量。该修饰符使用纪元时间戳 |
表 5.1 – PromQL 中可用的选择运算符
除了允许我们选择数据的运算符外,PromQL 还提供了一些运算符,用于比较多个数据集。
两个数据集之间的运算符
有些数据由单一度量轻松提供,而其他有用的信息则需要从多个度量中创建。以下运算符允许你将数据集进行组合。
| 名称 | 语法 | 运算符 | 作用范围 |
|---|---|---|---|
| 算术运算符 | a + b |
+、-、*、/、% 和 ^ |
对瞬时向量和标量进行算术运算;作用范围取决于 a 和 b 的数据类型。需要注意的是,向量会在所有标签上进行匹配。 |
| 比较运算符 | a == b |
==、!=、>、<、>= 和 <= |
基于比较过滤瞬时向量和标量;作用范围取决于 a 和 b 的数据类型。 |
| 聚合运算符 | sum by (``label) (a) |
sum()、min()、max()、avg()、group()、stddev()、stdvar()、count()、count_values()、bottomk()、topk() 和 quantile() |
对单一瞬时向量进行聚合操作。 这些运算符提供了 without 和 by 子句,以修改结果按标签分组的方式。 |
| 一对一向量匹配 | a + on b |
on() 和 ignoring() |
将向量匹配修改为特定标签(on)或忽略某标签(ignoring) |
| 使用组修饰符进行一对多/多对一向量匹配 | a + group_left b |
group_left() 和 group_right() |
在多对一或一对多匹配的情况下,修改向量匹配。分组可以使用标签列表来包含标签在结果中 |
| 使用逻辑运算符进行多对多向量匹配 | a and b |
and、or 和 unless |
在多对多匹配的情况下,基于标签和 a、b 的值之间的逻辑运算修改向量匹配 |
表 5.2 – PromQL 中可用的比较运算符
向量匹配是一个最初会让人感到困惑的话题;为了澄清这一点,我们来考虑向量匹配的三种情况 —— 一对一、一对多/多对一 和 多对多。
默认情况下,当组合向量时,所有标签名称和值都会被匹配。这意味着对于每个向量元素,运算符会尝试从第二个向量中找到一个匹配的元素。让我们来看一个简单的例子:
-
10{color=blue,smell=ocean} -
31{color=red,smell=cinnamon} -
27{color=green,smell=grass} -
19{color=blue,smell=ocean}*8{color=red,smell=cinnamon}*14{color=green,smell=jungle}*29{color=blue,smell=ocean}*39 {color=red,smell=cinnamon}*29{color=blue}*39{color=red}*41{color=green}
当color=blue和smell=ocean时,A{} + B{}的结果是10 + 19 = 29,而当color=red和smell=cinnamon时,A{} + B{}的结果是31 + 8 = 29。其他元素与这两个向量不匹配,因此会被忽略。
当我们使用on (color)进行向量求和时,我们只会根据color标签进行匹配;因此,现在这两个绿色元素会匹配并被求和。
当向量A和向量B之间存在一对一关系时,这个例子是有效的。然而,有时也可能存在多对一或一对多的关系 —— 也就是说,向量 A 或向量 B 中可能有多个元素与另一个向量的元素匹配。在这些情况下,Prometheus 会报错,并且必须使用分组语法。让我们看另一个例子来说明这一点:
-
7{color=blue,smell=ocean} -
5{color=red,smell=cinamon} -
2{color=blue,smell=powder} -
20{color=blue,smell=ocean}*8{color=red,smell=cinamon}*14{color=green,smell=jungle}*27{color=blue,smell=ocean}*13{color=red,smell=cinamon}*22{color=blue,smell=powder}
现在,我们在向量color=blue中有两个不同的元素。group_left命令将使用向量22中的标签,当在group_right操作符中进行匹配时,行为将朝着相反的方向进行。
最后的选项是多对多的向量匹配。这些匹配使用逻辑运算符and、unless和or来组合向量A和B的部分元素。让我们看一些例子:
-
10{color=blue,smell=ocean} -
31{color=red,smell=cinamon} -
27{color=green,smell=grass} -
19{color=blue,smell=ocean}*8{color=red,smell=cinamon}*14{color=green,smell=jungle}*10{color=blue,smell=ocean}*31{color=red,smell=cinamon}*27{color=green,smell=grass}*10{color=blue,smell=ocean}*31{color=red,smell=cinamon}*27{color=green,smell=grass}*14{color=green,smell=jungle}
与前面的示例不同,这里没有使用数学运算符,因此元素的值来自向量A,但只有与向量B中的逻辑条件匹配的A元素会被返回。
现在我们了解了运算符,让我们在看一个实际的 PromQL 写作示例之前,快速介绍一下 PromQL 函数。我们将在 Writing PromQL 部分探讨它们的实际用法。
函数
PromQL 提供约 60 种不同的函数。可以在 Prometheus 网站上找到完整的函数列表:prometheus.io/docs/prometheus/latest/querying/functions。
现在我们已经看过 PromQL 中可用的函数,让我们探索编写一个 PromQL 查询。
编写 PromQL
尽管语言的技术描述对于参考是有用的,但本节将遵循构建查询的过程,以便可以在上下文中看到语言。在接下来的几节中,我们将使用在前一节中介绍的选择器、运算符和修饰符编写实际的示例。
指标选择
当我们查看指标标签时,我们看到您可以使用 metric_name{} 语法在 PromQL 中选择指标。这可以直接键入查询中的 app_frontend_requests_total。如果没有,请使用 Metric 下拉菜单选择此指标。您应该看到类似于 Figure 5.3 中的结果。这种选择方法返回一个瞬时向量,如 Figure 5.4 中所述。
返回范围向量的语法与 Figure 5.5 中描述的类似。我们只需要添加我们感兴趣的范围 - metric_name[range]。范围必须包括时间单位,可以从毫秒(ms)到年(y)。重要的是要注意,使用范围向量的查询需要以 Instant 查询类型运行。如果选择了 Range 或 Both(默认),那么您将收到错误。以下是您将看到的错误示例:

图 5.6 – 在范围查询中使用范围向量时出错
时间序列选择和运算符
由于时间序列由一组唯一的标签组成,我们可以扩展我们的查询,仅查看特定数据 - 例如,仅请求目标为 OpenTelemetry 演示应用程序的购物车 API。以下步骤将过滤我们的查询,仅显示目标为 /api/cart 终端的请求:
- 切换到 Results 面板右上角的 Table 视图:

图 5.7 – 在 PromQL 结果中使用表视图
- 将鼠标悬停在目标值上,您应该看到这个图标:

图 5.8 – 值的过滤器
-
单击加号图标,您将看到我们有一个新的标签过滤器,我们的 PromQL 现在如下所示:
app_frontend_requests_total{target="/api/cart"}。 -
让我们只显示
GET方法的请求;你可以使用=来实现:检查字符串的精确匹配。例如,target="/api/cart"只会在target标签为/api/cart/时匹配。 -
!=:检查是否与精确匹配不同。target!="/api/cart"会匹配所有情况,除了target标签为/api/cart/的情况。 -
=~:检查是否与正则表达式匹配。例如,target=~"/api/.*"会在target标签以/api/开头时匹配。这包括/api/cart/、/api/horse/和/api/cart/foo/bar/。 -
!~:检查是否与正则表达式不匹配。target!~"/api/.+"会在target标签为/api/或/checkout/时匹配,但不会匹配/api/cart/、/api/horse/和/api/cart/foo/bar/。
当我们查看表格时,应该还会看到一个名为 metric_name{} 的列,它等同于 {__name__="metric_name"}。
我们已经选择了数据并将其筛选到感兴趣的端点,但对请求进行的原始计数难以解读。让我们看看如何使用函数将这个计数转换为更有用的信息。
函数、聚合和运算符
PromQL 是一种嵌套语言,因此要对选定的数据集应用函数,只需将数据选择放入函数中。到目前为止,我们的查询如下所示:
app_frontend_requests_total{target="/api/cart",method="GET"}
这个查询返回每个采样点的请求计数。对于大多数目的,我们更关心的是命中该端点的请求的速率。这将使我们能够回答诸如峰值速率是多少,或者现在的速率是否比某个时间点的速率高或低等问题。获取这些信息的函数是 rate() 函数。我们可以将当前查询插入到该函数中,如下所示:
rate(app_frontend_requests_total{target="/api/cart",method="GET"}[$__rate_interval])
rate 函数接受一个范围向量作为输入,因此我们添加了特殊的 [$__rate_interval] 时间变量。这是 Grafana 的一个功能,指示 Grafana 根据我们选择的数据源的抓取间隔来选择一个合适的间隔。这个功能简化了选择正确速率间隔的技术性操作。聚合和其他运算符也使用类似的过程。
现在我们知道如何获取 /api/cart 端点的请求速率,让我们看一个另一个示例查询。
HTTP 成功率
一个常见的 服务水平指标 (SLI) 用于 Web 应用程序,是 HTTP 请求的 成功率。用简单的语言来说,这就是成功的 HTTP 请求数与总 HTTP 请求数的比率。我们将在第九章中讨论选择良好 SLI 的过程。
像下面这样的 PromQL 查询将为 app_frontend_requests_total 指标生成成功率 SLI:
sum by (instance) (rate(
app_frontend_requests_total{status=~"2[0-9]{2}"}[5m]))
/
sum by (instance) (rate(app_frontend_requests[5m]))
我们可以将这段代码拆解如下:
-
使用
app_frontend_requests_total{status=~"2[0-9]{2}"}[5m],我们选择具有status标签且值在200到299之间的app_frontend_requests指标样本。这使用正则表达式来选择标签范围,并且它是一个五分钟范围的区间向量。对于熟悉正则表达式的用户,Grafana 需要对反斜杠进行转义。 -
rate()函数计算成功请求的每秒平均速率。该函数返回一个瞬时向量。 -
之前的函数将所有数据分组到初始时间序列中。然而,对于这个查询,我们不关心方法、目标或任何其他标签。相反,我们关心的是某个特定实例的应用程序是否出现故障,因为一个故障实例可能会被许多正常实例掩盖。为此,我们使用
sum by (instance) ()聚合函数。 -
查询的最后一行与第一行相同,但去除了标签选择器,因此我们得到的是 总 请求。
-
最后,我们使用算术运算符 (
/) 将成功请求除以总请求数。此查询的输出将是一个数字,当大多数请求成功时,它接近 1;当出现故障时,随着每个请求的失败,值将趋向于 0。
另一个常见的衡量项目是对服务请求的 持续时间。持续时间通常表示为直方图数据,PromQL 提供了许多统计工具,帮助我们理解用户的体验。让我们看一下以下查询:
histogram_quantile(
0.95, sum(
rate(
http_server_duration_milliseconds_bucket{}[$__rate_interval])
) by (le)
)
http_server_duration_milliseconds_bucket 指标是一个直方图,其命名约定中包含 _bucket。histogram_quantile() 函数接受该直方图数据,并为我们提供第 95 百分位的持续时间。这是通过直方图数据中的 le(小于或等于)标签计算得出的。虽然使用平均值进行此类计算可能很诱人,但百分位数能为我们提供更细致的数据理解。第 95 百分位意味着 95% 的样本持续时间小于或等于返回的值。
Grafana 提供了若干有用的函数,帮助理解查询:
-
在查询组件上方有一个标题为 Explain 的滑块。打开此滑块将逐步展示查询的执行过程。
-
此外,在查询组件上方有一个名为 Kick start your query 的按钮。点击它将提供一些初始查询。
-
在 选项 部分下方是查询 检查器。它将提供有关查询的详细信息,例如总请求时间和返回的数据。
这里是一张截图,显示了这些选项的位置:

图 5.9 – 查询的有用函数
希望你现在对 PromQL 的基础知识有了很好的掌握,并且知道有哪些资源可以用来进一步学习。虽然查询数据是 Grafana 日常工作的一个重要部分,但了解度量数据是如何收集的也是很有帮助的。
已设置的 OpenTelemetry 演示还会从单节点 Kubernetes 集群、节点上的 kubelet 实例和底层主机生成度量数据。我们鼓励你探索这些度量数据,看看你能发现什么。
我们已经了解了如何查询存储在 Prometheus 兼容系统中的数据。现在,让我们看看如何从你的服务中收集数据。
探索数据收集和度量协议
在第二章中,我们介绍了四种当前用于从现代软件中收集数据的常用协议——StatsD和DogStatsD,OpenTelemetry 协议(OTLP),以及Prometheus。我们还介绍了简单网络管理协议(SNMP),它广泛用于网络和计算领域。在本节中,我们将探讨这些协议的一些特点。
度量数据的收集有两种方法,推送和拉取。在推送协议中,应用程序或基础设施必须配置一个目标地址来发送度量数据。在拉取协议中,应用程序或基础设施配置为暴露度量数据,供其他服务请求。两种方法各有优缺点,同时也需要意识到潜在的安全隐患。在接下来的子节中,我们将深入探讨每种协议。
StatsD 和 DogStatsD
我们将 StatsD 和 DogStatsD 放在一起讨论,因为它们在本章所讨论的内容上是相同的。
8125是其默认设置。这些是使用 StatsD 时需要考虑的事项:
-
StatsD 使用 UDP 进行传输。这更倾向于优先考虑传输速度,而非确保交付的可靠性。
-
该协议不支持应用程序与接收服务之间的身份验证。根据环境的不同,这可能成为一个安全隐患。
值得注意的是,尤其是在 Kubernetes 中,常见的做法是将 StatsD 接收器暴露在localhost:8125上,从而限制暴露范围并为应用程序提供一个标准。
StatsD 在数据收集代理中有广泛的支持,通常通过贡献的接收器实现。OpenTelemetry 收集器、FluentBit、Vector、Beats、Telegraf 和 StatsD 守护进程都支持该协议。Prometheus 提供了一个导出器,将 StatsD 格式的度量数据转换为 Prometheus 抓取端点;这是一个建议的中间步骤,用于完整的 Prometheus 迁移。
DogStatsD 的支持不如其衍生自的 StatsD 格式;它为 StatsD 提供了一组扩展的指标。原生支持 DogStatsD 数据采集的代理包括 Vector 和 Datadog 自家的代理。OpenTelemetry 采集器目前不支持此功能,但正在讨论将其加入,Datadog 也是 OpenTelemetry 项目的积极参与者,因此这一点可能会发生变化。
OTLP
OTLP 也是一个 推送协议,因此需要知道目标位置。像 StatsD 一样,OTLP 通常通过标准接收端点 localhost:4317(localhost:4318(HTTP))来实现。OTLP 支持 gRPC 和 HTTP,并且支持客户端与服务器之间的认证和确认。OTLP 还提供了多个提升使用体验的功能,例如 服务器控制的限流 和 GZIP 压缩。
OpenTelemetry 正在积极开发中,因此这些信息可能会发生变化。由于该项目是多个主要厂商的合作,来自这些厂商的代理程序正在越来越多地支持 OTLP 指标。尽管其他采集工具不支持 OTLP 输入,但 OpenTelemetry 采集器支持来自多种来源的输入。这意味着 OTEL 采集器非常适合支持混合环境。Vector 采集代理也提供了这种多功能性,大多数关于 OTEL 采集器的说法同样适用于它。
Prometheus
与 StatsD 和 OTLP 不同,Prometheus 是一个 拉取协议。客户端应用程序需要配置一个端点来提供指标,然后配置一个与 Prometheus 兼容的抓取器,在特定的时间间隔内收集这些指标。这些指标通常暴露在 /metrics 端点上,尽管一些框架会以不同方式实现(例如 Spring Boot 的 /actuator/Prometheus)。
可能看起来使用拉取配置会增加所需的配置步骤。然而,使用拉取方法确实减少了应用程序对其运行环境所需的配置信息。例如,如果有 0 或 10 个客户端读取其指标,应用程序的配置保持不变。这个拉取模式也与 Kubernetes 中应用程序的存活和就绪端点模式非常契合。
为了帮助服务器配置,Prometheus 提供了广泛的服务发现选项,涵盖多个不同平台,包括 Kubernetes、DNS 和 Consul。这些发现选项包括匹配特定名称并在存在标签时收集数据,这一范围的选项使得在需要时能够实现相当复杂的架构。
Prometheus 格式具有良好的采集器支持;Prometheus、OTEL Collector、Grafana Agent、Vector、Beats 和 Telegraf 都支持采集这些指标。
SNMP
SNMP 比我们在这里讨论的其他协议更为复杂,因为它包含了许多用于管理和监控网络连接设备的功能,例如交换机和物理服务器。SNMP 的监控方面是一个拉取协议,即管理实例连接到设备上的代理软件并拉取数据。SNMP traps 还有额外的功能,允许设备以数据推送的方式向管理者报告事件。这些 traps 经常被用于追踪度量数据。值得注意的是,使用 SNMP 时,安全性可能会成为一个问题,具体取决于配置方式。如果配置不当,SNMP 会提供显著的攻击面。
SNMP 得到了很好的支持,因为该协议自 1988 年以来一直在使用,并且得到了硬件供应商的良好支持。
我们现在已经讨论了如何使用 PromQL 查询数据,以及数据是如何生成和收集的,现在让我们来探讨 Grafana 如何存储度量数据。
理解数据存储架构
时间序列数据库 (TSDBs) 理想地用于处理度量数据,因为度量需要在特定时间点记录数据,而 TSDB 被结构化为便于记录和查询这些数据。有多种 TSDB 可供选择,但由于本书专注于 Grafana,因此我们将在本节中仅讨论 Graphite、Prometheus 和 Mimir。本节的目的是让你理解数据的存储结构,并概述 Mimir 如何帮助组织将数据扩展到超越 Graphite 和 Prometheus 能力的水平。
Graphite 架构
Graphite 有多个组件;我们将在此讨论存储组件 Whisper。Whisper TSDB 使用扁平文件结构,其中每个唯一的时间序列都是一个固定大小的文件。这个大小由在 Whisper 中配置的分辨率和保留策略来决定。为了进行搜索,必须读取这些文件中的每一个,这会迅速变得昂贵,特别是在磁盘 I/O 上。由于没有内建的管理数据冗余的项目,Graphite 也无法保证写入的数据会免于丢失或损坏。
然而,Graphite 引入的写入数据的协议尽管已显老化,但仍然相关,因此 Grafana Cloud 为已经使用该技术的团队提供了一个 Graphite 数据接收端点和查询端点。
Graphite 是一个早期的度量标准,于 2008 年引入;先前提到的查询速度和数据完整性的限制导致了 Prometheus 的诞生,接下来我们将讨论 Prometheus。
Prometheus 架构
Prometheus 将数据存储在不可变的 block 中,block 覆盖一个固定的时间范围(默认是两小时)。在一个 block 中包含若干个 chunks,这些 chunks 的大小上限为 512 MB;这些文件包含了采样的值。与这些 chunks 一起的是元数据文件——index 和 meta.json。index 文件包含一个表格,记录了 block 中的标签以及指向所有样本在相关 chunks 中位置的引用。高基数的度量标签会导致 index 文件大小的巨大增加,并降低读取性能。meta.json 文件包含如 block 中的最小和最大时间戳,以及包含的样本、序列和 chunks 的统计信息,以及所使用的版本。
为了处理接收到的数据,Prometheus 还使用了一个 head block,它类似于用于存储的 block,但它允许写入。这使得可以收集完整的两小时数据块,等到数据块完成时,再创建 index 和元数据。这个过程包括将数据持久化到磁盘上的功能,以防止数据丢失。head block 包含一个 meta.json 文件,记录了已接收的数据。当两小时时间块结束时,会创建一个新的 head block,旧的 head block 会转变为一个标准的 block,并创建 index 和 chunks。
下图展示了一个虚构的 Prometheus TSDB 的结构,其中突出了 blocks、chunks、index 和元数据文件以及 WAL:

图 5.10 – Prometheus TSDB
Prometheus 中的 Prometheus TSDB 实现有限,因为它使用本地存储,本地存储没有原生的集群或复制功能。虽然可以改善这些方面,但其根本限制在于只有一个节点执行读写操作。在适当的情况下,这些限制是完全可以接受的。然而,当 TSDB 扩展以接受多个活跃的时间序列时,需要做出更改。处理这些情况正是 Mimir 设计的初衷。
Mimir 架构
Mimir 使用相同的基础 TSDB 存储结构。然而,与 Prometheus 不同,Mimir 原生支持对象存储来存储块文件。支持的存储包括 Amazon S3、Google Cloud Storage、Microsoft Azure Storage 和 OpenStack Swift。
通过利用对象存储,Mimir 能够解决 Prometheus 所遇到的扩展问题,通过增加新的数据摄取服务实例来实现。Mimir 将传入的数据流分配到特定的每租户 TSDB,并将每个数据流分配给一个摄取服务实例。像 Prometheus 一样,数据通过摄取器写入内存和 WAL,当块完成时,它被写入对象存储。为了提供弹性,Mimir 会将这些数据流写入多个摄取器,并且一个压缩服务将处理合并对象存储中冗余块的过程,并删除重复样本。
类似于写路径的水平可扩展性,Mimir 也扩展了读路径。它通过将传入的查询拆分成更短的时间范围来实现这一点。然后,它将这些更小的查询单元分发给多个查询实例。通过这样做,Mimir 再次利用底层对象存储的优势,实现数据的快速返回。
下图显示了 Mimir 的读写路径:

图 5.11 – Mimir 架构
指标显示的是聚合数据,如请求的总次数。当探索一个异常的指标值时,查看一个示例会很有帮助。在那些通过追踪和指标进行仪表化的应用中,示例允许我们在指标数据中记录一个样本追踪。让我们来看看这个功能的实际应用。
在 Grafana 中使用示例
示例是 Grafana 中的功能,允许我们从系统的聚合视图(通过指标提供)切换到单个请求的详细视图(通过追踪提供)。示例需要在采集层进行配置,然后发送到存储层。
当示例可用时,你可以通过以下步骤查看示例:
- 在查询下打开选项,并切换示例滑块:

图 5.12 – 示例切换按钮
- 示例将作为星星出现在指标图表上:

图 5.13 – 指标中的示例
将鼠标悬停在单个示例上时,将通过在指标视图中显示来自示例追踪的信息来扩展指标数据。我们将在第六章中更详细地解释这些字段,但一些显著的字段包括进程运行时的名称和版本以及span_id,这些在纯粹的指标视图中通常无法获取:

图 5.14 – 示例信息
- 通过示例,你还可以从查看指标数据切换到查看相关追踪,方法是点击与 Tempo 查询(****Tempo)按钮:

图 5.15 – 在 Tempo 中打开示例
我们将在第六章中详细讨论跟踪的具体内容,但这应当为你提供一个良好的介绍,帮助你在度量标准中使用这种数据。
总结
在本章中,我们详细探讨了度量标准。我们了解了在 PromQL 中可用的所有操作符,并使用该语言编写了两个查询。在掌握了查询知识的基础上,我们查看了收集数据的工具以及应用程序共享数据的各种协议。接着,我们了解了 Prometheus 的架构,并看到 Mimir 如何将 Prometheus 的概念转化为一个高度可扩展的数据处理工具,能够满足任何规模组织的需求。我们最后探讨了 Exemplars,为聚合数据提供了一个具体的数据示例,帮助我们更好地理解度量标准中的数据。
下一章将探讨 Grafana Tempo 中的跟踪工作原理,展示如何利用 Exemplars 以及日志追踪和跨度信息来为组织的客户创建一个真正可观察的系统。
第六章:使用 Grafana Tempo 进行追踪技术细节
Grafana Tempo 是 Grafana 提供的第三款遥测存储工具;它提供了存储和查询追踪数据的能力。本章将介绍 Tempo 查询语言(TraceQL)。TraceQL 可用于选择和过滤由应用程序生成的追踪数据,从而收集跨追踪的见解;该语言与 LogQL 和 PromQL 非常相似,但针对追踪数据进行了定制。在本章中,我们将探索主要的追踪协议以及如何使用它们输出应用程序的追踪数据;这将帮助你在应用程序中做出明智的选择,选择合适的协议或在收集数据时支持哪些协议。接下来,我们将探索 Tempo 的架构,以了解它如何满足可扩展的追踪平台需求。
本章将涵盖以下主要主题:
-
介绍 Tempo 和 TraceQL 查询语言
-
探索追踪协议
-
理解 Tempo 架构
技术要求
在本章中,你将使用演示应用和 Grafana Cloud 实例(在 第三章 中设置)。你可以在 GitHub 仓库中的 github.com/PacktPublishing/Observability-with-Grafana/tree/main/chapter6 找到本章的代码。你还可以在 packt.link/fJVXi 找到 Code in Action 视频。
更新 OpenTelemetry 演示应用
对于本章,我们提供了一个更新的 OTEL-Collector.yaml,其中包含额外的追踪配置。这个更新的配置位于 GitHub 仓库的 chapter6 目录中。更新过程的完整细节可以在 GitHub 仓库中的 README.md 文件中找到。
要将此更新的配置应用到 OpenTelemetry Collector,请按照以下步骤操作:
-
使用 Helm 升级 Collector:
$ helm upgrade --version '0.73.1' --values chapter6/OTEL-Collector.yaml --values OTEL-Creds.yaml owg open-telemetry/opentelemetry-collector NAME: owg-otel-collector LAST DEPLOYED: Sat Aug 19 12:42:36 2023 NAMESPACE: default STATUS: deployed REVISION: 4 … -
验证升级是否成功:
$ kubectl get pods --selector=component=standalone-collector NAME READY STATUS RESTARTS AGE owg-otel-collector-594fddd656-tfstk 1/1 Terminating 1 (70s ago) 2m8s owg-otel-collector-7b7fb876bd-vxgwg 1/1 Running 0 3s你的追踪数据现在将拥有更多标签,并且还将生成服务图和跨度指标。
现在我们的本地安装已更新,让我们从探索第三种查询语言 TraceQL 开始。
介绍 Tempo 和 TraceQL 查询语言
Tempo 和 TraceQL 是我们将在本书中深入探索的最新工具和查询语言。像 LogQL 一样,TraceQL 是以 PromQL 为灵感构建的,为开发者和运维人员提供了一套熟悉的过滤、聚合和数学工具,帮助在指标、日志和追踪数据之间实现可观察性流。
让我们快速了解 Tempo 如何查看追踪数据:
-
Trace 收集:在第二章中介绍了,trace(或分布式 trace)是一组数据,表示一个请求在系统中的传播。traces 通常从多个应用程序收集。每个应用程序将 spans 发送到某种收集架构,最终发送到 Tempo 进行存储和查询。
-
Trace 字段:以下图表介绍了 trace 的简化结构,类似于在第四章中看到的日志的简化结构,以及在第五章中看到的 traces:

图 6.1 – 包含四个 span 的 trace 简化视图
在第二章中,我们介绍了一个 trace 的常见字段。在前面的图示中,我们可以看到四个 span 都具有相同的 trace_id,它是整个 trace 的唯一标识符。每个 span 都有一个唯一的标识符,即 span_id。每个 span 还记录了它的来源,通过 parent_id 字段来表示。最后,记录了开始和结束时间。这个简化的视图排除了 OpenTelemetry 协议 (OTLP)、Zipkin 和 Jaeger 中的一些字段,这些字段用于捕捉大量的上下文信息。我们将在本章后面讨论这些内容。
现在我们已经看过 trace 数据的结构,接下来我们来探索 Tempo 接口,以及如何查询数据。
探索 Tempo 特性
在本节中,我们将介绍 Tempo 的主要功能,它是 Grafana 中的追踪平台,以及它的查询语言 TraceQL。在第四章和第五章中,我们介绍了 LogQL 和 PromQL 语言,它们专注于选择日志或度量数据,并提供详细功能来对选定的数据进行强大的分析。目前,PromQL 仅提供选择 trace 数据的功能。尽管有强大的工具可以选择这些数据,但目前没有工具进行分析。这种功能是产品的最终目标,但我们想要强调的是 Tempo 在 v2.3.x 版本中的当前状态。
让我们从探索 Tempo 的用户界面开始,看看它如何呈现 trace 数据。
Tempo 接口
用于探索 Tempo 数据的主要视图分为两部分,查询编辑器和trace 视图。在下图中,查询编辑器位于左侧,trace 视图位于右侧。当你首次进入视图时,你只会看到查询编辑器。点击 trace ID 或 span ID 时,trace 视图会被打开:

图 6.2 – 查询编辑器(左)和 trace 视图(右)
结果面板是上下文相关的。如果我们使用 TraceQL 进行搜索,它将返回一个匹配的追踪和跨度列表;这在前面的截图的左侧显示。然而,如果我们搜索特定的追踪 ID,我们将在右侧显示追踪视图,在那里我们可以探索该追踪中的跨度。
在查看查询面板时,让我们来看一下我们可以使用的两种不同的搜索模式,如下所示:

图 6.3 – 搜索模式
前面的截图中显示的两种搜索模式如下:
-
基本搜索模式:在这个模式下,系统会提供下拉菜单,供你选择感兴趣的追踪。对于初次使用 Tempo 并且希望快速获取数据的人来说,这非常有用,但我们在本书中不会探讨这个搜索模式。请注意,此模式将在 Grafana 10.3 中被弃用。
-
TraceQL 模式:这个模式允许你使用 TraceQL 以非常精细的方式搜索你需要的数据。这是默认的搜索模式。
除了这些,还有三种搜索模式可用:
-
Loki 搜索模式:你应该对这个模式感到熟悉,它在第四章中有所介绍;它可以在 Tempo 中使用,因此你可以非常快速地在包含追踪和跨度 ID 的日志与完整追踪视图之间切换。
-
JSON 文件模式:这个模式允许直接导入并查看以 JSON 格式保存的追踪。结合导出功能,它使得有趣的追踪可以简单地保存和共享。在导出的 JSON 文件中探索数据是理解追踪中使用的底层数据结构的一个很好的练习。
-
服务图模式:收集分布式追踪的最强大功能之一就是能够可视化这些服务之间的连接。这个工具为任何人提供了一个清晰的图形表示,展示系统中应用程序之间是如何相互通信的。该功能结合了指标和追踪来表示系统的当前状态。工具还会用红色标示出出错的请求,用绿色标示出成功的请求。
下方截图显示了服务图的默认视图:

图 6.4 – 服务图
除了表示服务之间的连接,前面的截图还显示了请求率和响应的平均延迟。在服务图上方,显示了请求、错误和持续时间(RED)指标。我们将在第九章中详细讨论这些指标。
在撰写时,OpenTelemetry 和 Tempo 的这一部分正在积极开发中,作者期待即将推出的功能。
现在我们已经看过 Tempo 的界面,接下来让我们了解如何使用 TraceQL 查询追踪数据。
探索 Tempo 查询语言
像 Prometheus 和 Loki 一样,Tempo 提供了一种查询语言,TraceQL。现在你已经熟悉了 Tempo 的界面和跟踪结构,让我们来探索 TraceQL 的功能。
字段类型
TraceQL 使用两种字段类型,内在字段 和 属性字段。让我们详细了解这些字段:
-
status: 该值可以是error、ok或未设置(null) -
statusMessage: 可选的文本,用于阐明状态 -
duration: 跨度的开始和结束之间的时间 -
name: 操作或跨度的名称 -
kind: 该值可以是server、client、producer、consumer、internal或unspecified,其中unspecified是回退值 -
traceDuration: 跟踪中所有跨度的开始和结束之间的毫秒数 -
rootName: 跟踪中第一个跨度的名称 -
rootServiceName: 跟踪中第一个服务的名称 -
span.http.method和span.app.ads.ad_response_type。*resource.container.id和resource.k8s.node.name。
为了提高查询效率,最佳实践是始终在属性查询中包含 span. 和 resource.。然而,当你不确定某个字段是跨度还是资源时,可以使用前缀 . 来进行查询,例如 .http.method 或 .k8s.node.name。
查看单个跨度时,你可以看到在 跨度属性 和 资源属性 下可用的字段。这个展开视图显示了包含在跨度中的字段:

图 6.5 – 跨度的属性
现在你已经很好地掌握了在 Tempo 中搜索跟踪时可用的字段,让我们来看一下如何搜索跟踪和跨度。
选择跟踪和跨度
TraceQL 提供了工具来选择在仪表盘中显示的数据,或仅仅探索系统的当前状态。以下表格描述了这些工具:
| 名称 | 语法 | 操作符 | 范围 |
|---|---|---|---|
| 字段选择器 | {field = " value"} |
=, !=, >, >=, <, <=, =~, !~ |
选择特定字段值的跨度 |
| 字段表达式 | {field1="value1" && field2="value2"} |
&&,|| |
选择多个字段值匹配的跨度 |
| 逻辑操作符 | {field1="value1} && {``field1="value2} |
&&,|| |
选择逻辑检查为 true 的跨度,这可以检查多个字段。 |
| 结构操作符 | {field1="value1"} > {``field2="value2} |
>,>>,~ |
在第二个过滤器中搜索跨度,检查它们与第一个过滤器的关系。后续将更详细解释这些操作符。 |
表 6.1 – TraceQL 中可用的选择操作符
结构操作符提供了执行查询的能力,考虑到条件是否在跟踪中的上游(父级)或下游(子级)满足。让我们看一些示例:
-
>或 子操作符 表示直接子跨度,如下所示:{.service.name="frontend"} > {.service.name="productcatalogservice"}上述行将搜索来自产品目录服务的所有跨度,其中前端服务是直接父节点。
-
>>或 后代运算符 表示任何后代,例如以下内容:{.service.name="frontend"} >> {.service.name="cartservice"}这将搜索来自购物车服务的所有跨度,其中前端服务是追踪中的父节点,但它可能首先经过其他服务,例如结账服务。
-
~或 兄弟运算符 表示共享相同父节点的任何跨度,例如以下内容:{.service.name="frontend"} ~ {.service.name="frontend"}这将搜索任何多次访问前端的跨度。在演示应用中,前端服务将是父节点。
这些运算符允许我们选择数据。TraceQL 还允许工具对追踪数据执行聚合和数学函数操作。
聚合器和算术
聚合器和数学函数允许进行更复杂的查询。它们可以显示跨所有追踪信息的聚合数据。以下表格中描述了一些聚合器:
| 名称 | 语法 | 运算符 | 作用域 |
|---|---|---|---|
| 计数聚合器 | | count() > 10 |
count() |
按跨度集中的跨度总数对返回的跨度进行精炼 |
| 数值聚合器 | | avg(duration) > 20ms |
avg()、max()、min() 和 sum() |
按字段对跨度集中的返回跨度进行精炼 |
| 算术运算符 | {field1 < field2 * 10} |
+、-、*、/ 和 ^ |
对数字字段执行算术运算 |
表 6.2 – TraceQL 中的聚合和数学运算符
值得注意的是,TraceQL 在编写时处于积极开发阶段,因此此运算符列表预计会不断增长。
现在你已经了解了如何搜索追踪数据,让我们讨论如何无缝地在数据类型之间切换,以便获得完整的视图。
数据类型之间的转换
当正确地进行仪表化时,应用程序将生成数据,可用于在追踪、日志和指标之间切换,从而真正理解发生了什么。
让我们考虑以下跨度,其中在checkoutservice中发现了一个错误。这可能是实际商店中的一个问题,因为它表明客户到达了结账页面,却因某种原因无法完成销售:

图 6.6 – 查找错误的日志
Tempo 的查询界面提供了一个有用的链接,service_name 和 service_namespace 字段可用于查询 Loki。以类似的方式,服务可以将追踪上下文(traceId 和 spanId)注入到其日志输出中(如果可用)。然后,可以配置 Loki 提供上下文链接到 Tempo,以查看追踪视图。最后,正如在 第五章 中提到的,指标可以呈现示例,这使得用户能够查看来自指标图表的样本追踪。
我们已经探索了查看应用程序生成数据的方法。在下一节中,我们将了解用于生成 Grafana Tempo 跟踪数据的不同协议。
探索跟踪协议
在第二章中,我们介绍了三种主要的跟踪协议,OTLP、Zipkin 和 Jaeger。在本节中,我们将探讨这些协议的一些特点、它们的支持情况,以及如何在你编写的软件服务中使用它们。我们还将讨论这些协议用于将上下文传递给其他服务的不同头部。一个跟踪协议由一组头部组成,这些头部会添加到由仪表化应用程序发出的 HTTP 请求中。这些头部传递每个 span 的信息到下游服务。一旦所有这些 spans 被收集,它们就形成了一个完整的分布式跟踪。
主要的跟踪协议有哪些?
首先,让我们看看主要跟踪协议的特点和支持情况——OTLP、Zipkin 和 Jaeger。
OTLP
OTLP 跟踪支持 C++、.NET、Erlang、Go、Java、JavaScript、PHP、Python、Ruby、Rust 和 Swift。在流行的开发框架中,如 Spring、Django、ASP.NET 和 Gin,都有很好的 OTLP 支持。由于支持范围广泛,最佳实践是查阅你选择的框架文档,了解如何对应用程序进行仪表化;在大多数情况下,仪表化操作可能仅仅是添加几行依赖项。
跟踪本质上是一个分布式过程,已经有几个标准用于传播跟踪字段。这意味着应用程序在处理跟踪时可能需要使用不同的 HTTP 或 gRPC 头部,这取决于它们操作环境中的其他应用程序。OTLP 原生支持 W3C TraceContext、B3 和 Jaeger 传播头部,并且支持用于传播其他上下文信息的 W3C 行李头部。B3 和 Jaeger 头部的支持意味着使用 Zipkin 和 Jaeger 库仪表化的应用程序得到原生支持。然而,其他跟踪头部,如 AWS 的 X-Ray 协议,并未作为主流分发的一部分进行维护。如果使用这些协议,建议使用相关厂商的 OpenTelemetry 分发版本——例如,当 X-Ray 在监控环境中使用时,可以使用 AWS Distro for OpenTelemetry(aws.amazon.com/otel/)。
在数据收集领域,OTLP 跟踪数据得到了 OpenTelemetry Collector、Grafana Agent、通过插件支持的 FluentBit 和通过插件支持的 Telegraf 的良好支持。
Zipkin
Zipkin 支持 C#、Go、Java、JavaScript、Ruby、Scalar 和 PHP,通过支持的库;以及 C++、C、Clojure、Elixir、Lua 和 Scala,通过社区支持的库。与 OTLP 一样,Zipkin 在流行的开发框架中也有很好的支持,因此在进行应用程序仪表化时,最好查阅框架文档。
Zipkin 仅原生支持 B3 传播头。然而,由于框架提供了对不同追踪协议的可插拔支持,因此在应用程序中实现对其他传播头的支持可能相对容易。
在数据收集方面,Zipkin 被 OpenTelemetry Collector、Grafana Agent 以及 Zipkin 本身的原生工具支持。
Jaeger
我们在这里包括 Jaeger 是出于历史原因,但不推荐采用它。Jaeger 最初由Uber开发。在 2022 年 1 月之前,Jaeger 为 Java、Python、Node.js、Go、C#和 C++提供了 SDK,这些 SDK 支持 OpenTracing API。OpenTelemetry 是由 OpenTracing 和 OpenCensus 项目合并而成。Jaeger 现在推荐使用 OpenTelemetry SDK 来为应用程序提供监控。对于已经使用 Jaeger 客户端库的应用程序,OpenTelemetry 提供了迁移指南:opentelemetry.io/docs/migration/opentracing/。
Jaeger 库支持 Jaeger、Zipkin 和 W3C TraceContext 头,但不支持任何其他的传播格式。
在 Jaeger 得到积极支持期间,数据收集器对 Jaeger 的支持并不广泛;该协议的预期使用方式是在本地环境中将数据收集到 Jaeger 后端。OpenTelemetry Collector 和 Grafana Agent 确实提供了对 Jaeger 追踪的接收器,并允许您在应用程序迁移到 OpenTelemetry 协议时收集这些追踪数据。
现在你已经熟悉了追踪协议,我们来看看用于在使用分布式追踪的服务之间传播信息的头部。
上下文传播
分布式追踪在 Web 技术中相对较新,万维网联盟(W3C)在 2021 年 11 月将Trace Context作为推荐标准,而Baggage格式目前仍处于工作草案阶段。追踪以两种不同的方式记录信息:
-
每个应用程序将追踪和跨度信息发送到收集代理
-
应用程序还使用 HTTP 或 gRPC 头共享数据,这些数据会被接收方应用程序获取
由于追踪技术是一项新技术,在官方的 W3C Trace Context 头标准确定之前,曾使用过一些非正式的标准格式。为了提供一些追踪技术的历史背景,我们将探讨以下格式:
-
Jaeger/Uber 头
-
Zipkin B3 头
-
W3C Trace Context 头
-
W3C 行李头
Jaeger/Uber 头
Jaeger 库历史上使用了以下头格式;我们为历史参考包括了这些内容,因为这些格式应该被视为已弃用,推荐使用 W3C Trace Context。
Jaeger 中使用的两个 HTTP 头是uber-trace-id和uberctx,它们的格式如下:
uber-trace-id: {trace-id}:{span-id}:{parent-span-id}:{flags}
uberctx-{baggage-key}: {baggage-value}
uber-trace-id头的示例如下:
uber-trace-id: 269daf90c4589ce1:5c44cd976d8f8cd9:39e8e549de678267:0x01
让我们拆解一下uber-trace-id头中的各个字段:
-
trace-id:此字段是 64 位或 128 位的随机数,且为十六进制编码。在示例中,这是269daf90c4589ce1。 -
span-id和parent-span-id:这是 64 位的随机数,并且是十六进制编码的。分别为5c44cd976d8f8cd9和39e8e549de678267。 -
flags:此字段用于传递附加信息,例如是否对跟踪进行采样。在此示例中,其值为0x01。
在 uberctx 行李头部中,字段如下:
-
baggage-key:这是一个唯一的字符串,用于命名头部。 -
baggage-value:这是一个将被百分比编码的字符串。作为一个概念,行李将在 W3C baggage 部分进一步探讨。
Zipkin B3 头部
Zipkin 库使用 B3 头部;与 Uber 头部不同,Zipkin 历史上将每个字段分离到自己的头部中,如以下代码片段所示:
X-B3-TraceId: {TraceId}
X-B3-ParentSpanId: {ParentSpanId}
X-B3-SpanId: {SpanId}
X-B3-Sampled: {bool}
X-B3-Flags: 1 OR header absent
b3: {TraceId}-{SpanId}-{SamplingState}-{ParentSpanId}
让我们分解这些头部:
-
X-B3-TraceId:与 Jaeger 格式类似,TraceId是 64 位或 128 位的十六进制编码。以下是此头部的一个示例,显示其发送方式:X-B3-TraceId: 68720d6346a16000531430804ce28f9c -
X-B3-ParentSpanId和X-B3-SpanId:这些是 64 位并且是十六进制编码的。 -
X-B3-Sampled:其值为1或0,尽管早期实现可能使用true或false。 -
X-B3-Flags:此头部用于传播调试决策。 -
b3:Zipkin 在 W3C Trace Context 标准引入之前就已存在。为了帮助过渡到新标准,Zipkin 引入了b3头部。Zipkin 的后续版本可以使用这两个头部和 W3C Trace Context 头部来实现互操作性。b3头部完全匹配 W3C Trace Context 中使用的tracestate头部,表示将其他头部合并为一个映射。
W3C Trace Context
W3C 指定了一对标准头部,如下所示:
traceparent: {version}-{trace-id}-{parent-id}-{trace-flags}
tracestate: vendor specific trace information
让我们将这些头部分解成它们的组成部分:
-
traceparent中的各个字段如下:-
trace-id是一个十六进制编码的 16 字节数组(128 位)。 -
parent-id是一个十六进制编码的 8 字节数组(64 位);此字段等同于 Jaeger 和 B3 中的span-id或SpanId,表示生成该头部的服务所使用的跨度 ID。它与 B3 的ParentSpanId不同,因为它可用于表示发起被跟踪过程的上游服务。 -
version字段是另一个十六进制编码的 8 位字段;它表示所使用的标准版本。目前仅存在版本 00。 -
trace-flags是另一个十六进制编码的 8 位字段。在 W3C 标准的版本 00 中,唯一可用的标志是表示是否正在进行采样。
-
-
tracestate用于编码特定于供应商的信息。虽然traceparent是一个固定格式,任何采用该标准的供应商都必须使用它,tracestate则为供应商提供了一个空间,以确保追踪数据能够传播,并允许他们根据需要使用和编码这些数据。关于这个头部字段的唯一要求是,内容将是一个以逗号分隔的键值对列表。
W3C 行李箱
tenantId,但是当一个应用程序向下游应用程序发起请求时,那个应用程序可能并不需要了解tenantId,就能够处理该请求。一个行李箱头部允许我们将tenantId字段传播到下游应用程序。下游应用程序可以在其可观察性工具中使用这个字段,同时又不会污染其数据模型,避免引入与业务无关的字段。这有效地将可观察性问题与应用程序问题分开。需要注意的是,行李箱头部中包含的数据可以被任何检查网络流量的人查看,因此不应使用它来共享敏感信息。
W3C baggage 头部看起来像这样:
baggage: key1=value1,key2=value2;property1;propertyKey=propertyValue,…
所有字段必须进行百分号编码;整个头部最多包含 64 个成员,且最大大小为 8,192 字节。使用行李箱头部为系统提供了一种标准化的方式来传播上下文信息。
我们现在已经讨论了应用程序如何产生追踪数据,以及如何将其共享,包括与收集代理和其他应用程序共享。接下来,让我们花些时间看看 Tempo 如何处理和存储数据。
理解 Tempo 架构
像 Loki 和 Mimir 一样,Tempo 利用对象存储,如 Amazon S3、Google Cloud Storage 和 Microsoft Azure Blob Storage。随着组件在读写路径上的水平扩展,Tempo 在数据量增加时具备了极好的扩展能力。
以下图表展示了 Tempo 使用的架构:

图 6.7 – Tempo 架构
Tempo 的写入路径包括以下几个部分:
-
分发器:分发器负责接收跨度,并根据跨度的追踪 ID 将其路由到正确的 ingester 服务实例。
-
Ingester:Ingester 负责将跨度组合成追踪,批量处理多个追踪并将其打包成块,同时为查询编写布隆过滤器和索引。一旦一个块完成,Ingester 还会将数据刷新到后端。
-
度量生成器:度量生成器是一个可选组件;它接收来自分发器的跨度,并利用这些跨度生成服务图和跨度度量(例如,速率和错误时长)。这些数据随后会被写入度量后端。
Tempo 的读取路径包括以下组件:
-
查询前端:前端负责接收查询并将其拆分为更小的分片,基于将被读取的数据块(由 ingester 创建)来返回请求的数据。然后,这些分片会被排队等待查询器处理。
-
查询器:该组件负责查找请求的数据,若数据块已经被刷新,则从后端获取数据,若数据块仍在收集,则直接从 ingester 获取数据。
压缩器,作为一个独立组件,负责优化后端存储的使用。
现在我们已经完成了对 Tempo 系统架构的探索,你已经看到了工具的所有主要组件,以及如何通过 Tempo 进行分布式追踪,从而帮助你清晰地了解你运行的系统组件。
总结
在本章中,你学习了如何使用 TraceQL 查询存储在 Tempo 中的追踪数据,这将帮助你为仪表板构建查询,利用这一丰富的数据源。你已经探索了 Tempo 的用户界面,因此你将能自信地在界面中操作。结合第四章和第五章中学到的技能,你将能够在 Grafana 中自信地在日志、度量和追踪数据之间切换,从而观察你所工作的系统。
我们详细了解了在为应用程序添加监控时,可以使用的不同协议和库,看到这些工具在不同编程语言中的支持程度。我们还探讨了用于在应用程序之间传播追踪数据的 HTTP 头信息。这将帮助你选择最佳的方式来为应用程序添加监控,并了解如何与已经启用了追踪的应用程序进行协作。
最后,我们看了 Tempo 的架构,以及它如何横向扩展以支持你的组织处理所需的任何数量的追踪数据。通过这些知识,你将理解如何操作 Tempo 的安装,并监控其各个组件。
在下一章中,我们将通过展示如何从你的基础设施层收集数据来结束第二部分的内容,无论是来自 AWS、Azure 或 GCP 等云服务提供商,还是来自 Kubernetes 集群。
第七章:使用 Kubernetes、AWS、GCP 和 Azure 查询基础设施
本章将介绍捕获来自各大常见云基础设施提供商的遥测所需的设置和配置。你将了解 Kubernetes 的不同选项。此外,你将探讨使 Grafana 能够查询来自云服务商(如Amazon Web Services(AWS)、Google Cloud Platform(GCP)和 Azure)的数据的主要插件。你还将研究如何处理大量遥测数据的解决方案,尤其是在直接连接不可扩展的情况下。本章还将介绍在遥测数据到达 Grafana 之前进行过滤和选择的选项,以实现安全性和成本优化。
本章将涵盖以下主要主题:
-
使用 Grafana 监控 Kubernetes
-
使用 Grafana Cloud 可视化 AWS 遥测
-
使用 Grafana 监控 GCP
-
使用 Grafana 监控 Azure
-
最佳实践与方法
技术要求
在本章中,你将使用 Grafana Cloud 实例与多个云提供商进行协作。你将需要以下内容:
-
一个 Grafana Cloud 实例(在第三章中设置)
-
Kubernetes 和 Helm(在第三章中设置)
-
拥有 AWS、GCP 和 Azure 云提供商管理员权限的账户
使用 Grafana 监控 Kubernetes
Kubernetes 设计时就考虑到了监控,因此它为任何希望使用 Grafana 监控其本身或运行在其上的工作负载的人提供了多种选项。本节将重点介绍 Kubernetes 的监控,因为我们在前几章中已经使用 OpenTelemetry 演示应用程序处理了 Kubernetes 工作负载。
在第三章中介绍的 OpenTelemetry Collector 提供了接收器、处理器和出口程序,用于实现 Kubernetes 监控和数据收集与增强。下表列出了这些组件,并对每个组件做了简要说明:
| OpenTelemetry 组件 | 描述 |
|---|---|
| Kubernetes 属性处理器 | Kubernetes 属性处理器将 Kubernetes 元数据附加到遥测数据,为关联提供必要的上下文。 |
| Kubeletstats 接收器 | Kubeletstats 接收器通过拉取机制从 kubelet API 获取 Pod 指标。它收集安装在每个节点上的节点和工作负载指标。 |
| Filelog 接收器 | Filelog 接收器收集写入 stdout 和 stderr 的 Kubernetes 和工作负载日志。 |
| Kubernetes 集群接收器 | Kubernetes 集群接收器通过 Kubernetes API 收集集群级别的指标和实体事件。 |
| Kubernetes 对象接收器 | Kubernetes 对象接收器收集来自 Kubernetes API 的对象,例如事件。 |
| Prometheus 接收器 | Prometheus 接收器使用 Prometheus scrape_config 设置抓取指标。 |
| 主机度量接收器 | 主机度量接收器从 Kubernetes 节点抓取度量数据。 |
表 7.1 – Kubernetes 接收器
现在让我们探讨每个组件及其实现方式。
Kubernetes 属性处理器
OpenTelemetry Kubernetes 属性处理器可以自动发现 Pods,提取其元数据,并将提取的元数据添加到跨度、度量和日志中,作为额外的资源属性。它为你的遥测提供了必要的上下文,能够将你的应用程序的度量、事件、日志、跟踪和信号与 Kubernetes 的遥测数据进行关联,如 Pod 的度量和跟踪。
通过处理器传递的数据默认通过传入请求的 IP 地址与 Pod 关联,但可以配置不同的规则。
OpenTelemetry Collector Helm chart 配置有多个预设。例如,启用 kubernetesAttributes 预设时,它会将必要的 RBAC 角色添加到 ClusterRole,并会在每个启用的管道中添加一个 k8sattributesprocessor:
presets:
kubernetesAttributes:
enabled: true
Kubernetes 自带元数据用于文档化其组件。当使用 kubernetesAttributes 预设时,默认情况下会添加以下属性:
-
k8s.namespace.name:Pod 部署的命名空间。 -
k8s.pod.name:Pod 的名称。 -
k8s.pod.uid:Pod 的唯一标识符。 -
k8s.pod.start_time:Pod 创建的时间戳,在理解 Pod 重启时非常有用。 -
k8s.deployment.name:应用程序的 Kubernetes 部署名称。 -
k8s.node.name:Pod 所运行节点的名称。由于 Kubernetes 会将 Pods 分布到所有节点上,了解是否有节点出现特定问题非常重要。
此外,Kubernetes 属性处理器还会使用 Pod 和命名空间的标签与注释,为你的遥测创建自定义资源属性。
有两种方法可用于获取和关联数据,即 extract 和 pod_association。你可以在 Helm chart 中启用它们,如以下代码所示:
k8sattributes:
auth_type: 'serviceAccount'
extract:
pod_association:
让我们更详细地了解这些方法:
-
extract:该方法允许使用元数据、注释和标签作为遥测的资源属性。它有以下选项:-
metadata:用于从 Pod 和命名空间提取值,如k8s.namespace.name和k8s.pod.name -
annotations:用于提取 Pod 或命名空间注释中指定键的值,并将其作为资源属性插入:- tag_name: attribute-name key: annotation-name from: pod -
labels:用于提取 Pod 或命名空间标签中指定键的值,并将其作为资源属性插入:- tag_name: attribute-name key: label-name from: pod
annotations和labels也可以与正则表达式一起使用,从值中提取部分内容作为新的资源属性。 -
-
pod_association:此方法将数据与相关的 Pod 关联。您可以配置多个源,代理会按顺序尝试这些源,直到找到匹配的为止。pod_association有一个sources选项,用于标识要用于关联的资源属性,或者它会使用连接上下文中的 IP 属性:pod_association: - sources: - from: resource_attribute name: k8s.pod.ip - sources: - from: resource_attribute name: k8s.pod.uid - sources: - from: connection
权限
如果您没有使用 kubernetesAttributes 预设,则需要提供必要的权限,以允许访问 Kubernetes API。通常,能够访问 Pod、命名空间和 ReplicaSet 资源就足够了,但这取决于您的集群配置。
Kubeletstats 接收器
Kubeletstats 接收器连接到 kubelet API,以收集关于节点和在节点上运行的工作负载的度量,因此推荐的部署模式是 DaemonSet。默认情况下,度量会收集 Pod 和节点的指标,但也可以额外配置以收集来自容器和卷的指标。
以下代码显示了 Kubeletstats 接收器的配置:
receivers:
kubeletstats:
collection_interval: 60s
auth_type: 'serviceAccount'
endpoint: '${env:K8S_NODE_NAME}:10250'
insecure_skip_verify: true
metric_groups:
- node
- pod
- container
文件日志接收器
尽管不是 Kubernetes 特定的接收器,文件日志接收器是 Kubernetes 中最受欢迎的日志收集机制。它通过操作符链式处理日志数据,从文件中获取并解析日志。
OpenTelemetry Collector Helm 图表具有 logsCollection 预设,用于将必要的 RBAC 角色添加到 ClusterRole 中,并且它会将 filelogreceiver 实例添加到每个启用的管道中(我们将在第十章中解释 includeCollectorLogs):
presets:
logsCollection:
enabled: true
includeCollectorLogs: false
如果自己配置,您需要手动将角色和filelogreceiver添加到管道中。一个基本的文件日志接收器显示了要包括和排除的内容,以及其他处理选项:
filelog:
include:
- /var/log/pods/*/*/*.log
exclude:
- /var/log/pods/*/otel-collector/*.log
start_at: beginning
include_file_path: true
include_file_name: false
此外,还可以应用操作符进行日志处理、过滤和解析。
以下是文件日志接收器解析器的列表:
-
json_parser:用于解析 JSON -
regex_parser:用于执行正则表达式解析 -
csv_parser:用于解析以逗号分隔的值 -
key_value_parser:用于处理结构化的键值对 -
uri_parser:用于处理结构化的 web 路径 -
syslog_parser:用于处理标准的 syslog 日志格式
Kubernetes 集群接收器
Kubernetes 集群接收器顾名思义,使用 Kubernetes API 服务器收集集群的度量和事件。该接收器用于获取关于 Pod 阶段、节点状态和其他集群级操作的信息。接收器必须作为单个实例部署,否则数据会重复。
以下是一个集群接收器配置示例:
k8s_cluster:
auth_type: serviceAccount
node_conditions_to_report:
- Ready
- MemoryPressure
allocatable_types_to_report:
- cpu
- memory
metrics:
k8s.container.cpu_limit:
enabled: false
resource_attributes:
container.id:
enabled: false
Kubernetes 对象接收器
Kubernetes 对象接收器可用于从 Kubernetes API 服务器收集任何类型的对象。与 Kubernetes 集群接收器一样,它必须作为单个实例部署,以防止数据重复。
该接收器可以通过使用 pull 或 watch 来拉取或监视对象:
-
当实现
pull时,接收器定期轮询 Kubernetes API 并列出集群中的所有对象。每个对象将被转换为其自己的日志。 -
当配置
watch时,接收器会创建一个与 Kubernetes API 的流,以便在对象更改时接收更新;这是最常见的用例。
让我们看一个 Kubernetes 对象接收器配置的示例:
k8sobjects:
auth_type: serviceAccount
objects:
- name: pods
mode: pull
label_selector: environment in (prod)
field_selector: status.phase=Running
interval: 15m
- name: events
mode: watch
group: events.k8s.io
namespaces: [default]
Prometheus 接收器
scrape_config选项由接收器支持。此实现和scrape_configs的示例可以在第五章演示项目代码中看到。以下是 Prometheus 接收器配置示例:
prometheus:
config:
scrape_configs:
- job_name: 'opentelemetry-collector'
tls_config:
insecure_skip_verify: true
scrape_interval: 60s
scrape_timeout: 5s
kubernetes_sd_configs:
- role: pod
Prometheus 接收器是有状态的,因此在使用时需要考虑以下几点:
-
接收器无法通过多个副本自动扩展抓取过程
-
使用相同配置运行多个副本将会多次抓取目标
-
要手动扩展抓取过程,每个副本需要配置不同的抓取配置
主机度量接收器
主机度量接收器使用多种抓取器从主机收集度量指标;接收器需要访问主机文件系统卷才能正常工作。
表 7.2显示了可供抓取的度量指标。OpenTelemetry Collector Helm 图表有hostMetrics预设来添加必要的配置:
mode: daemonset
presets:
hostMetrics:
enabled: true
默认情况下,预设将每 10 秒抓取一次数据,这可能会为你的后端系统生成过多的度量指标。请注意这一点,并考虑将抓取间隔重写为 60 秒。下表还显示了使用预设时默认会抓取的度量指标:
| 度量抓取器 | 描述 | 使用 hostMetrics 预设时包含 |
|---|---|---|
| CPU | 抓取 CPU 利用率度量指标 | 是 |
| 磁盘 | 抓取磁盘 I/O 度量指标 | 是 |
| 负载 | 抓取 CPU 负载度量指标 | 是 |
| 文件系统 | 抓取文件系统利用率度量指标 | 是 |
| 内存 | 抓取内存利用率度量指标 | 是 |
| 网络 | 抓取网络接口 I/O 度量指标和 TCP 连接度量指标 | 是 |
| 分页 | 抓取分页和交换空间利用率以及 I/O 度量指标 | 否 |
| 进程 | 抓取进程计数度量指标 | 否 |
| 进程 | 抓取每个进程的 CPU、内存和磁盘 I/O 度量指标 | 否 |
表 7.2 – 主机度量接收器抓取器
现在让我们来看看我们的第一个云服务提供商 AWS 以及可用的连接选项。
使用 Grafana Cloud 可视化 AWS 遥测数据
有两种主要方式可以使用 Grafana Cloud 可视化你的 AWS 遥测数据:
-
Amazon CloudWatch 数据源:Amazon CloudWatch 遥测数据保留在 AWS 中,Grafana 被配置为在查询时远程读取数据
-
AWS 集成:AWS CloudWatch 遥测数据要么发送到 Grafana Cloud,要么被抓取并存储在 Grafana Cloud 中(Loki 中的日志和 Mimir 中的度量数据)。
让我们来看一下这两种选项的区别,以便了解集成选项或数据源选项哪个最适合你的使用场景。
亚马逊 CloudWatch 数据源
Grafana Cloud 支持亚马逊 CloudWatch,允许你在 Grafana 仪表板中查询、触发警报和可视化数据。要读取 CloudWatch 遥测数据,你需要配置 AWS 身份与访问管理(IAM)权限,并在数据源配置页面提供必要的认证信息。这不会将任何遥测数据存储在 Grafana 中;它仅在查询时获取数据。
现在让我们看看不同的配置步骤。
配置数据源
数据源可以通过CloudWatch菜单访问。对于现有数据源,可以在数据源搜索框中搜索CloudWatch。你将看到类似下图的界面。点击CloudWatch以打开设置页面:

图 7.1 – Grafana 连接数据源页面
设置页面需要提供建立连接所需的 AWS 配置详情,如下图所示。在这里,你还可以配置自定义指标的命名空间详情、日志查询超时以及 X-Ray 跟踪链接:

图 7.2 – 亚马逊 CloudWatch 数据源设置
使用亚马逊 CloudWatch 查询编辑器
CloudWatch 数据源配备了专门的查询编辑器,可以查询来自 CloudWatch 指标和日志的数据。
在数据浏览器中,你可以选择CloudWatch 指标或CloudWatch 日志作为源数据,如下图所示:

图 7.3 – 亚马逊 CloudWatch 查询编辑器
在构建器模式下使用指标编辑器,你可以通过指定命名空间、指标名称和至少一个统计数据来创建有效的指标查询。
日志编辑器提供了一个日志组选择器,允许你指定目标日志组,然后在查询编辑器中使用 AWS CloudWatch Logs 查询语言 docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html。
使用亚马逊 CloudWatch 仪表板
在数据源设置页面上,有一个仪表板标签,提供了一些预配置的仪表板,帮助你快速入门。
下图显示了可用仪表板的列表及导入详情(如果已经导入了仪表板,你将看到删除或重新导入的选项):

图 7.4 – 亚马逊 CloudWatch 预配置仪表板
现在让我们来看一下 AWS 集成选项。
探索 AWS 集成
AWS 集成选项可以添加到你的账户中。添加并配置后,它将作为连接可用。配置后,你将能够直接将指标和日志数据导入到 Grafana,因为数据保存在你的 Grafana Cloud 堆栈中,这为查询提供了时间优势。然后可以使用 LogQL 或 PromQL 查询这些指标和日志;有关详细信息,请参见 第四章 和 第五章。
现在让我们来看看不同的配置步骤。
配置集成
可以从 添加新连接 屏幕中的 aws 菜单访问 AWS 连接;你将看到类似以下的屏幕。你会看到这是一个 基础设施 连接,并标记为 指南。这意味着将提供全面的说明,帮助你连接账户并引导你完成过程:

图 7.5 – Grafana 添加新连接屏幕
选择 AWS 集成选项后,会向你展示几个集成选项 —— CloudWatch 指标、带 Lambda 的日志 和 带 Firehose 的日志 —— 如下图所示:

图 7.6 – AWS 集成屏幕
接下来,我们将讨论带有 Lambda 的 CloudWatch 指标和日志。
CloudWatch 指标
CloudWatch 集成功能允许你在不安装任何收集器或代理基础设施的情况下抓取 Amazon CloudWatch 指标。可以创建多个抓取作业来分离不同的关注点,但只能为带标签的 AWS 资源发现指标。
如前所述,此集成是引导式的,提供了所有必要的细节,可以通过使用基础设施即代码或手动连接并配置抓取作业来开始。以下截图展示了 CloudWatch 指标 配置 详情 屏幕:

图 7.7 – CloudWatch 配置详情屏幕
此外,还有一些预构建的仪表板可以直接使用。以下图示展示了在撰写本文时与集成选项一起提供的预构建仪表板列表:

图 7.8 – 示例 CloudWatch 指标仪表板
带 Lambda 的日志
启用 Lambda 集成的日志功能使你能够将 CloudWatch 日志发送到 Grafana Cloud。此集成将引导你部署一个 AWS Lambda 函数,该函数将 CloudWatch 日志转发到 Grafana Cloud Loki,在那里可以使用 LogQL 进行查询。第四章详细解释了 Loki 和 LogQL。
以下截图展示了 带 Lambda 的日志 配置屏幕,在这里你可以选择部署方式:

图 7.9 – 带有 Lambda 配置详情的日志
下图展示了配置步骤,屏幕上的指南会引导你完成日志集成的连接和配置:

图 7.10 – 带有 Lambda CloudFormation 配置的日志
现在让我们来看一下我们的第二个云服务提供商——GCP。
使用 Grafana 监控 GCP
Grafana Cloud 支持Google Cloud Monitoring,允许你在 Grafana 仪表盘中查询、触发警报和可视化数据。它不会在 Grafana 中存储任何遥测数据;它仅在查询时提取数据。
现在让我们来看一下配置数据源的步骤。
配置数据源
可以通过数据源搜索框中的Google Cloud Monitoring菜单访问数据源;你将看到类似于图 7.11所示的屏幕。点击Google Cloud Monitoring以打开设置页面。设置屏幕会提示你进行 Google 配置,以建立和测试连接。下面显示的是连接搜索结果屏幕:

图 7.11 – 连接搜索结果屏幕
下图中的Google Cloud Monitoring配置设置将引导你完成配置,帮助你选择身份验证方式,可以选择JSON Web Token(JWT)或GCE 默认 服务帐户:

图 7.12 – Google Cloud Monitoring 配置设置
根据你的 GCP 部署规模,你可能需要在设计时考虑任何关于令牌或服务帐户的限制。
Google Cloud Monitoring 查询编辑器
Google Cloud Monitoring 数据源自带有一个专用的查询编辑器,可以帮助你构建用于度量和 GCP 服务水平目标(SLOs)的查询,二者都返回时序数据(你将在第八章中了解更多关于时序数据的可视化)。可以使用构建器界面或 GCP 的监控查询语言(MQL)来查询度量数据。SLO 查询构建器帮助你以时序格式可视化 SLO 数据。要了解 GCP 服务监控的基本概念,请参阅 GCP 文档,网址为 https://cloud.google.com/stackdriver/docs/solutions/slo-monitoring。
下图中的Google Cloud Monitoring查询编辑器显示了三个可用选项:

图 7.13 – Google Cloud Monitoring 查询编辑器选择
让我们来看一下不同的 Explorer 查询类型:
- 指标查询:指标查询编辑器构建器帮助您选择指标,通过标签和时间进行分组和聚合,并为您要查询的时间序列数据指定时间过滤器:

图 7.14 – Google Cloud Monitoring 查询编辑器指标构建器
以下截图展示了 MQL 查询编辑器,它提供了一个接口,用于创建和执行您的 MQL 查询:

图 7.15 – Google Cloud Monitoring 查询编辑器指标 MQL 接口
MQL 语言规范的完整文档可以在 Google Cloud 网站上找到,网址为 cloud.google.com/monitoring/mql。
-
SLO 查询:SLO 查询构建器帮助您以时间序列格式可视化 SLO 数据。有关服务监控基本概念的文档,可以在 Google Cloud 网站上找到,网址为
cloud.google.com/stackdriver/docs/solutions/slo-monitoring。以下截图展示了 Google Cloud Monitoring 的 SLO 查询编辑器:

图 7.16 – Google Cloud Monitoring 查询编辑器指标 SLO 构建器
Google Cloud Monitoring 仪表板
在 数据源 | 设置 屏幕中,仪表板 选项卡列出了帮助您入门的一组预配置仪表板。以下截图展示了撰写时可用的仪表板列表以及导入详情(如果仪表板已经导入,可以选择删除或重新导入)。从列表中,您可以看到涵盖的各种 GCP 组件,包括防火墙、数据处理、SQL 等等:

图 7.17 – Google Cloud Monitoring 预构建仪表板
现在让我们来看一下第三个云服务提供商,Azure。
使用 Grafana 监控 Azure
Grafana Cloud 支持 Azure,可以在 Grafana 仪表板中查询、触发警报并可视化您的数据。这被称为 Azure Monitor 数据源。与其他云数据源一样,它不会在 Grafana 中存储任何遥测数据;它只会在查询时检索数据。
现在让我们一步步进行配置。
配置数据源
可以通过 数据源 搜索框中的 Azure Monitor 菜单访问数据源;您将看到类似以下的屏幕:

图 7.18 – Azure Monitor 的连接搜索结果屏幕
点击 Azure Monitor 打开设置页面。下图显示的 Azure Monitor 配置设置将引导您完成配置过程,帮助您通过 Azure Client Secret 配置设置身份验证,并测试连接:

图 7.19 – Azure Monitor 数据源设置屏幕
使用 Azure Monitor 查询编辑器
Azure Monitor 数据源配备了专门的查询编辑器,帮助您构建针对度量、日志、Azure 资源图和应用程序洞察跟踪的查询。
以下是 Azure Monitor 查询编辑器的截图,展示了四个选择:

图 7.20 – Azure Monitor 查询编辑器选择器
让我们详细看看这些选项:
-
度量查询:Azure Monitor 度量查询从 Azure 支持的资源中收集数字数据,这些资源可在 Microsoft Azure 网站上找到:
learn.microsoft.com/en-us/azure/azure-monitor/monitor-reference。度量只存储数字数据,并以特定的结构存储,这使得近实时检测平台健康状况、性能和使用情况成为可能。Azure Monitor 度量查询构建器如下所示:

图 7.21 – Azure Monitor 度量查询构建器
- 日志查询:Azure Monitor 日志查询从 Azure 支持的资源中收集和整理日志数据。可以访问各种数据类型,每种类型都有其定义的结构,并且可以使用 Kusto 查询语言(KQL)进行访问。KQL 的概述可以在 Microsoft Azure 网站上找到:
learn.microsoft.com/en-us/azure/data-explorer/kusto/query/。下图显示了 Azure Monitor 日志查询编辑器:

图 7.22 – Azure Monitor 日志查询编辑器
Azure Monitor 日志可以存储多种数据类型,每种类型都有自己的结构。更多详细信息,请参考 learn.microsoft.com/en-us/azure/azure-monitor/monitor-reference。
- 跟踪查询:Azure Monitor 跟踪查询可以看作是 Azure 应用程序洞察的底层实现。Azure 应用程序洞察服务为其工作负载提供应用程序性能监控(APM)功能。Azure Monitor 跟踪可以用来查询和可视化各种度量和跟踪数据。查询编辑器的界面如下所示:

图 7.23 – Azure Monitor 跟踪查询编辑器
-
Azure 资源图(ARG):ARG 服务通过提供跨多个 Azure 订阅进行可扩展查询的功能,扩展了 Azure 资源管理器的功能。这使得使用资源图查询语言查询 Azure 资源成为可能,非常适合查询和分析较大的 Azure 云基础设施部署。有关资源图查询语言的完整文档,请访问
learn.microsoft.com/en-us/azure/governance/resource-graph/samples/starter?tabs=azure-cli。以下示例查询显示按名称列出的所有资源:
Resources | project name, type, location | order by name asc下面是 ARG 查询编辑器的界面:

图 7.24 – Azure Resource Graph 查询编辑器
使用 Azure Monitor 仪表板
在 数据源 | 设置 屏幕中,仪表板 选项卡显示了一组预配置的仪表板,帮助你快速开始使用 Azure Monitor。在以下截图中,列出了为其设计了仪表板的各种 Azure 组件,包括应用程序、SQL 服务器和存储帐户:

图 7.25 – Azure Monitor 预构建仪表板
现在,让我们回顾一下本章中我们为每个云基础设施提供商介绍的最佳实践。
最佳实践和方法
本章提供了几种流行的云基础设施的概述。接下来,我们将讨论在任何应用程序或系统中实施可观察性时应考虑的一些最佳实践:
-
性能:检索遥测数据的过程可能会带来性能开销。例如,使用远程 Grafana 数据源时,遥测数据会在查询时通过较远的距离进行获取。与使用诸如 Loki、Mimir 和 Tempo 等 Grafana Cloud 数据源,在距离 Grafana 查询引擎较近的地方存储数据相比,这可能会引入延迟。如果性能至关重要,并且有选项将遥测数据传输到 Grafana,那么这可能是最佳选择。或者,许多数据源都提供缓存选项来提高查询速度;通过特定配置也可以改进查询速度。花时间理解你的数据,并确保以最佳方式使用它。
-
成本:除了将数据传输到 Grafana Cloud 增加的网络和存储成本外,在查询云提供商 API 时也可能产生费用。了解费用产生的地方非常重要,这可以确保在为你的系统设计可观察性解决方案时考虑到这些费用。
-
限制:通常,基础设施平台会配置一些限制以保护系统。这些有时是可以在谨慎考虑后放宽的软限制,但也可能是硬限制。在为特定平台选择解决方案之前,了解你的需求以及预期的数据量或查询事务量。你可以将这些与任何文档中列出的限制、API 密钥的使用情况或网络出站流量进行比较,从而验证系统是否能满足你的需求。
-
安全性:在本章中讨论的大多数配置选项,我们已识别出它们如何设置以实现关注点分离。通过拥有独立的数据源或对查询或摄取的数据进行其他控制,可以基于底层数据和用例提升安全防护水平。
重要提示
当本书即将出版时,Grafana Labs 发布了私有数据源连接(PDC),使管理员能够连接到任何网络安全的数据源,无论其托管在哪里。我们未在本书中涵盖这一主题,但它可能会引起读者的兴趣。
我们现在将通过总结来结束本章,并为下一章做好铺垫。
总结
在本章中,我们查看了各种常见的云基础设施提供商,从 Kubernetes 开始,并展示了可以与本书附带的示例项目一起使用的示例。接着,我们介绍了三大云提供商:AWS、GCP 和 Azure。我们提供了连接选项的概述,并展示了如何使用预构建的仪表板和数据探索器入门。最后,我们介绍了一些在所有可观测性集成中需要考虑的最佳实践。
在下一章中,我们将从将遥测数据导入 Grafana 转到使用仪表板可视化数据。这才是有趣的开始!
第三部分:Grafana 实践
在实践中,Grafana 被用于了解当前系统状态,并采取适当的行动为客户提供最佳结果。本部分将涵盖为实现这一目标可能需要的各种活动,并且在过程中应考虑的事项。你将学习如何展示数据,同时考虑受众的需求。你将探索如何建立一流的事件管理流程。你还将了解自动化和构建可观测性平台的策略。
本部分包含以下章节:
-
第八章**,使用仪表板展示数据
-
第九章**,使用警报管理事件
-
第十章**,使用基础设施即代码进行自动化
-
第十一章**,构建可观测性平台架构
第八章:使用仪表板显示数据
现在,我们已经一起探索了前几章所涉及的主题,并且对如何从 Grafana 中获取可访问的数据有了很好的理解。接下来,我们将一起创建我们的第一个仪表板,并查看可视化数据的不同方式。然后,我们将探索一些帮助你有效与仪表板沟通的概念和技巧,减少观众的认知负担。我们还将浏览一些社区资源,为你的仪表板提供灵感。最后,我们将分享一些管理仪表板制品的指导,帮助你在仪表板发展壮大的过程中保持组织性。
本章将涵盖以下主要内容:
-
创建你的第一个仪表板
-
进一步开发你的仪表板
-
在 Grafana 中使用可视化
-
定义仪表板的目的
-
高级仪表板技巧
-
管理和组织仪表板
-
案例研究 – 整体系统视图
技术要求
在本章中,你将使用 Grafana Cloud 实例的 Grafana 用户界面,并使用在第三章中设置的演示。此外,为确保你拥有所有数据源和设置,请确保已经在第六章中对你的堆栈进行了更新。让我们开始创建第一个仪表板吧。
创建你的第一个仪表板
仪表板是向用户传达重要且有时紧急信息的一种方式。在我们深入讨论设计技巧和最佳实践之前,让我们先熟悉一下 Grafana 的用户界面,开始创建一个简单的仪表板。我们在本书中使用的示例应用程序有一个前端商店;让我们来看一下我们从购物车 API 获取的请求数据。
要创建你的第一个面板和仪表板,请按照以下步骤操作:
-
在你的 Grafana 实例中,选择菜单中的Explore。
-
选择你的 Prometheus 数据源,这将标记为grafanacloud-
-prom(默认) 。 -
在Metric下拉菜单中,选择app_frontend_requests_total(前端应用程序的请求计数),在Label filters下拉菜单中,选择target = /api/cart作为过滤器(以限制结果仅显示购物车 API 的请求),然后点击运行查询。你应该会看到类似的数据:

图 8.1 – 应用前端请求
我们现在已经将时间序列数据呈现为图表。
-
要将此内容添加到仪表板中,在Explore窗口顶部选择添加下拉菜单按钮。
-
选择添加 到仪表板:

图 8.2 – 添加到仪表板菜单
- 在弹出窗口中,确保选择了新建仪表板,然后点击打开仪表板:

图 8.3 – 添加面板到仪表板
你现在将在屏幕上看到新的仪表盘及其第一个面板。正如你所见,这里有一些问题——图例难以阅读,数据没有太大意义,而且面板标题与数据无关:

图 8.4 – 新仪表盘视图
- 让我们进行一些小改动,稍微改进一下。从三点下拉菜单中选择编辑。面板编辑器将出现;你应该会看到如下内容:

图 8.5 – 面板编辑器
- 给面板起一个有意义的名称。我们在标题字段中输入了
前端请求:

图 8.6 – 查询选项
-
默认情况下,图表将显示来自范围和即时查询的数据,这在时间序列可视化中可能看起来很奇怪,因为你会看到时间线和单独的单值。将类型更改为仅范围。
-
点击应用按钮更新面板并返回仪表盘:

图 8.7 – 面板应用按钮
- 你现在将看到仪表盘面板名称应用于所显示的指标。点击仪表盘菜单栏上的保存图标:

图 8.8 – 保存仪表盘
- 给你的新仪表盘起一个有意义的名称,能够反映它的目的;我们这里有一个
前端仪表盘。

图 8.9 – 保存仪表盘面板
现在我们有了第一个仪表盘,但它非常简单,只有一个面板。它并没有有效传达太多信息,仅凭前端请求数量并不能显示我们在线商店的状况。让我们探索一下还能做些什么来改进它。
进一步开发你的仪表盘
现在让我们进一步开发仪表盘,并改进我们共享的信息。将仪表盘视为一个可以反复迭代的工作进展,并随着信息传达的完善而不断优化,这是确保准确传达信息的关键。在本节中,我们将使用一个示例,其中前端应用程序的请求数量不断增加,但这并不能告诉我们太多信息。显示这些请求的速率更加合理,因为我们将能够看到它们在应用程序中的到达速度。现在让我们进行这个修改:
- 从面板的三点下拉菜单中选择编辑,你将看到如下界面:

图 8.10 – 面板编辑器
- 在面板编辑器中,我们可以看到查询构建提示我们添加速率;它被蓝色框高亮显示。点击此提示,将建议的聚合添加到现有查询中(如果提示未出现,请点击操作按钮,选择速率,并设置$__rate_interval的范围):

图 8.11 – 速率查询
如你所见,图表现在显示了每秒进入我们商店的前端GET和POST请求的数量。这比之前更有用,但图例有些混乱,所以我们来清理一下。
-
展开位于 PromQL 查询预览下方的选项部分。
-
替换
{{method}}的内容,如图 8.12所示;这将从方法标签中提取值,作为图表图例的值。 -
在此期间,我们还可以将标题更改为反映我们现在显示的是速率,而不是计数,并添加一个有意义的描述,如下图所示:

图 8.12 – 面板更新
- 再次点击应用按钮更新面板并返回仪表盘。你应该会看到像下面这样的仪表盘:

图 8.13 – 我们的第一个仪表盘
如我们在前面的截图中所见,现在我们已经有了一个有意义的展示,展示了进入前端 API 的GET和POST请求的速率。仪表盘和面板的名称很好地反映了它们的目的,并且面板旁边还有一个新的i图标,当你将鼠标悬停在上面时,会显示你添加的描述。
现在,让我们看看 Grafana 中可用的可视化以及如何使用它们。
在 Grafana 中使用可视化
Grafana 提供了多种可视化选项,以支持你的各种使用场景和数据格式。例如,对于计数器和仪表量度类型,你可以使用Stat或Gauge可视化,直方图可以使用条形图或仪表图。日志可以使用表格可视化呈现,或者通过在时间序列图中生成来自日志的指标。你可以在 Grafana 网站上找到最新的插件可搜索列表:grafana.com/grafana/plugins/panel-plugins/。一个很好的地方是 play.grafana.org,你可以在这里尝试它们并获取可以在你自己仪表盘中使用的创意,网站上有所有面板可视化的仪表盘示例,以及各种数据类型。
要在面板编辑器中更改面板的可视化,你可以使用可视化选择器,位于右上角。选择它将显示一个可搜索的列表,并附带可视化的图形表示。你可以在以下截图中看到这一点:

图 8.14 – Grafana 可视化
让我们在我们的第一个仪表盘上尝试这个:
-
从面板的三点下拉菜单中,选择编辑。
-
从面板可视化列表中选择Stat。你应该会看到仪表盘面板变化,类似于以下样子:

图 8.15 – 状态可视化
为了更好地理解可用的选项,花点时间尝试不同的可视化效果,或花时间在 Grafana Play 上浏览那里的示例。一旦你了解了可用的可视化效果以及每个面板的不同配置,设计自己的仪表盘将变得更加轻松。
一个典型的面板配置通常包含以下项:
-
标题和描述:标题应帮助人们理解展示的数据,而描述则应补充或美化标题。
-
图例配置:图例应帮助解释展示的数据,并提供上下文和清晰度。它可以格式化以支持视觉处理数据,并且能够与视图互动,过滤数据以显示选中的项。
-
标准选项设置:用于控制单位、最大值和最小值、小数位数、显示名称以及配色方案的选项。
-
面板特定选项设置:每个可视化面板都可以有自己的面板配置。
-
阈值:这些用于控制显示的颜色、背景或数值,依据是否达到或超过数据阈值。
-
覆盖项:可以对数据应用自定义可视化设置,格式化并改变展示方式——例如,移除小数并显示单位标识符。
-
值映射:这些类似于覆盖项,用来改变数据的视觉表现。它们可以用来将返回的数值替换为基于数据匹配(包括范围和正则表达式)的颜色或数值,从而改变视觉呈现。
花时间熟悉一些主要可视化面板的配置,会增强你为用户构建和展示数据的信心。
现在让我们看一下几个设计概念,帮助你更有效地展示数据。
开发仪表盘的目的
在创建仪表盘时,非常重要的一点是它必须有一个明确的目标。你可以问自己三个关键问题,帮助你识别这些目标并得到答案:
-
目标用户是谁?
-
他们的需求是什么?
-
仪表盘将在哪里查看(大屏幕还是手机)?
一个仪表盘必须讲述一个故事或回答一个问题,但在回答这些问题之前,我们不能做任何事情。让我们参考第一章中介绍的角色,思考需要仪表盘的人群、他们的需求以及他们将在哪里查看仪表盘:
| 角色 | 需求 |
|---|
|
| Diego 开发者 | 获取我开发的系统中流量的洞察。这将帮助我了解客户如何使用我们的产品,并帮助我改进产品。通常,我需要调查错误,并深入挖掘错误的更多细节。 |
|
| Ophelia 操作员 | 事件发生时的问题可见性,系统状态通过清晰的指示器和颜色表示。信息需要简单易懂,一目了然。仪表板通常会显示在大屏幕上,但如果我正在调查一个问题,它也需要在我的电脑上显示。 |
|
| Steven 服务经理 | 总体而言,这是一个系统视图,帮助我看到更广泛的全貌。如果出现问题,我需要信息来识别谁能解决它。我将在电脑上查看这些信息。 |
|
| Pelé 产品经理 | 清晰而全面的度量标准,展示了我们的产品如何使用以及使用了哪些设备。我将在电脑上查看这些数据,通常我还想将其导出为电子表格以便进一步分析。 |
|
| Masha 经理 | 聚合数据对我很有用,展示了恢复率和容量的趋势,帮助我提前做好计划。我将在电脑上查看这些数据,但通过电子邮件接收定期的 PDF 报告也很有帮助。 |
表 8.1 – 仪表板用户与需求
捕捉最终用户需求并通过你创建的仪表板提供这些需求,将确保从你的可观察性平台中获取价值并提高用户采纳率。一旦你拥有了用户需求并分析了数据(以便了解哪些信息是重要的),你就可以开始整理你的仪表板。我们说是“整理”而不是“创建”,因为你要记住,你是在创建一个用来回答问题的工具,这个过程需要时间。在制作每个仪表板的过程中,不要害怕尝试不同的风格、布局和可视化效果。确保在不同的展示需求下进行测试;无论是大型墙面屏幕显示,还是电子邮件中的 PDF 文件,你都需要确认它的显示效果正确。
让我们来看看一些有助于展示的技巧。
高级仪表板技巧
为了有效地与我们的仪表板进行沟通,我们可以使用布局和一些技术特性来提升我们的表现。让我们开始详细了解其中的一些技巧:
-
布局技巧:为了有效地传达信息,你需要考虑一些布局技巧,这些技巧能真正让你的信息脱颖而出。包括以下几点:
-
在概览面板中使用简短的标题,以使其更加清晰易读。
-
添加描述,说明如何使用这些信息以及它的目标用户是谁,以便为用户提供最佳的理解数据的机会。
-
使用Stat带有小趋势图的可视化来突出显示关键指标,并将它们放在仪表板的顶部。
-
将面板以网格形式呈现,视觉上引导观众浏览你的仪表盘并控制他们的焦点。
-
不要将太多面板塞入一个仪表盘中,这样会让内容难以消化。相反,使用数据链接到其他仪表盘,并将数据分隔开。
-
使用透明面板在仪表盘上引入视觉间距,帮助突出关键信息。
-
使用行将相关面板和数据分组在一起,创建数据的上下文。
-
使用行的折叠功能来隐藏仪表盘加载时的某些数据;这也有助于性能,因为在行展开之前不会运行那些查询。
-
将相似的可视化项分组,使仪表盘更容易阅读,这样有助于处理所呈现的数据。
-
-
now-15m显示过去 15 分钟的数据。 -
使用转换来将数据以更易消化的格式呈现。转换 标签和可用的转换方法在下图中显示:

图 8.16 – 转换选择屏幕
- 使用注释;用来自其他数据源的丰富事件或甚至手动注释标记图表上的关键点,以传达重要事件:

图 8.17 – 注释
现在让我们来看一下如何开发一些良好的实践,来保持对仪表盘的控制。
管理和组织仪表盘
随着仪表盘和使用它们的团队数量增加,你将需要一种更轻松的管理方式。Grafana 提供了文件夹、标签和权限,使我们能够更好地组织。你可以从主 仪表盘 屏幕创建文件夹、移动和删除仪表盘,并对它们进行加星标记,正如下图所示:

图 8.18 – 仪表盘屏幕
从仪表盘 设置 屏幕,你可以为单个仪表盘添加或移除标签,如下图所示:

图 8.19 – 仪表盘设置
让我们看看可用的文件夹、标签和权限设置:
-
文件夹:
-
提供简便的组织和分组方式
-
通过在文件夹级别划分权限来增强安全性
-
-
标签:
-
在搜索相关仪表盘时非常有用
-
使用颜色编码便于视觉识别
-
-
权限:
-
控制对文件夹及其仪表盘的访问
-
仅为不需要编辑的用户提供查看权限
-
根据需要隐藏文件夹
-
可供个人用户和团队使用
-
现在你已经理解了相关概念,接下来我们来看一个案例研究,帮助我们为其中一个人物角色开发仪表盘。
案例研究 – 整体系统视图
现在我们将一起走过开发 Steven 服务经理仪表盘的过程。如果你还记得在 第一章 中提到的,他从事服务交付工作。他希望组织的服务能尽可能平稳运行。
我们将从一个用例开始;在本章的前一个部分,开发仪表板目的,我们记录了 Steven 提出的以下需求:
“总体来说,这是一个能帮助我看到更大局面的系统视图。如果有问题,我需要相关信息来识别谁能解决它。我将通过电脑查看这个信息。”
这可以细分为以下几个方面:
-
顶层系统视图
-
问题指标(用于突出问题)
-
需要时提供更多细节
-
协助识别谁能提供帮助
然后我们需要通过文档和与人交谈来收集信息。
我们在整本书中都使用了 OpenTelemetry 演示应用程序;幸运的是,架构图可以在 https://opentelemetry.io/docs/demo/architecture/ 上找到,这将帮助我们更好地理解系统。
让我们来看一下 OpenTelemetry 演示系统的架构图:

图 8.20 – OpenTelemetry 演示系统架构
我们还将查看这些应用程序正在收集的遥测数据。这可以通过自己探索 Grafana 来完成;现在我们有了系统名称和应用流。或者,我们可以与开发者 Diego 交流,获取他对系统的见解。
如果你是自己探索,这是建立研究仪表板的好时机。这里你可以在探索和发现有趣数据时添加面板。我们在本章早些时候通过第一个仪表板做了这个,先是前端请求,然后改进它以显示前端请求的速率。否则,你可以开始建立一个数据备忘录仪表板,收集你可能想要使用的数据;现在不用担心布局或可视化。
为了帮助我们选择有用的度量指标,我们可以使用一种方法论,比如 Google 的 Site Reliability Engineering 手册中提出的 四大黄金信号(https://sre.google/sre-book/monitoring-distributed-systems/#xref_monitoring_golden-signals)。还有其他流行的方法,比如 利用率、饱和度、错误(USE)方法和 速率、错误、时长(RED)方法,我们将在下一章讨论这些方法。
让我们快速看一下四大黄金信号:
-
延迟:处理请求的时间
-
流量:系统承受的需求量
-
错误:请求失败的比率
-
饱和度:系统服务的负载程度
当你有一些关键的度量数据可以使用时,你可以开始构建你的仪表板。记住,仪表板应该讲述一个故事或回答一个问题;Steven 说他希望有一个顶层系统视图,能够突出显示问题,并在需要时访问更详细的信息。我们可以按照以下步骤进行:
-
让我们从仪表盘的第一行开始,创建第一视图区域。通过选择详细描述流量通过我们系统的指标,我们可以使用如统计信息(带时间轴)的可视化来突出显示。引导观众,Steven,从左到右展示最重要的信息。
这是一个包含时间轴可视化的统计信息示例,用于第一视图区域:

图 8.21 – 系统概览
其他可视化方式,如仪表盘,适合表示系统的饱和度。
为了确保Steven首先关注最重要的信息,我们可以通过阈值、覆盖和数值映射来增强我们的面板。在某些面板中,我们甚至可以将更多的上下文作为注释覆盖在上面。
-
然后,我们需要找到一种方式来传达更详细的信息,并根据需要展示的信息量来决定这一点。我们需要问两个问题:
-
我们能否在这个仪表盘上展示详细信息(这里有足够的空间吗)?
-
我们是否需要深入其他更专注的仪表盘?
对于我们的用例,我们将在相同的仪表盘上进行工作。为了支持Steven识别在事件发生时他需要支持的人,我们可以做如下操作:
-
我们可以在行中逻辑地分组我们的可视化。每一行可以代表一个团队,第一个面板可以是一个文本面板,用于共享联系信息并提供如何与团队互动的详细信息。这意味着使用仪表盘时认知负担大大减少,帮助Steven更快地解决问题。
-
我们还可以使用面板描述来共享有助于观众,包括Steven,理解数据的有用信息,仪表盘链接到支持页面的提示也会有所帮助。
-
为了更好地展示更详细的信息,我们可以使用诸如表格面板这样的可视化,并结合颜色编码来提供视觉辅助,帮助更快地处理信息。
-
这里是一个包含顶级洞察以及更详细和有方向性的(即识别负责或支持的团队)面板和行的示例:

图 8.22 – 详细的仪表盘
从这个虚构的例子中可以看出,构建一个有用的仪表盘需要多次迭代。这个过程不仅仅涉及遥测数据,还需要更多的元素,但最终的结果意味着Steven能够完成他的工作,并有最大的机会提供客户满意度。
现在让我们通过几句话来结束这一章,讨论如何通过仪表盘支持你的开发工作。
总结
在本章中,我们探讨了仪表板的不同组件,并查看了我们需要考虑的各种细节。这些技巧需要时间来建立,所以请以同样的方式来开发你的仪表板,尽早构建一些简单的东西,然后在此基础上不断迭代。我们讨论了面板可用的可视化效果,以及来自像play.grafana.org等网站的灵感。玩得开心,尝试不同的方式展示你的数据,找到你喜欢的风格。最后,我们介绍了一些技巧和窍门,以帮助你改进仪表板的制作,最后总结了一些简单的想法,帮助你管理你的仪表板。
在下一章,我们将学习事件管理以及来自 Grafana 的强大工具,这些工具可以支持事件管理。
第九章:使用警报管理事件
本章将探讨事件管理的概念。我们将讨论如何建立一个世界级的事件管理流程,这个流程既能人性化地对待事件响应人员,又能避免他们的过度疲劳。章节将明确这一责任,从高级领导团队到响应呼叫的工程师。它还将介绍建立一个能够处理事件并为客户提供稳定体验的组织的重要概念。在流程建立之后,我们将解释如何考虑服务并挑选关键指标,以便查看当前的服务水平,而不会被噪音所干扰。
本章还将探讨 Grafana 提供的三个用于事件管理的工具。首先是Grafana Alerting,用于监控指标和日志中的故障,并触发通知给响应团队。然后是Grafana OnCall,它在 Alerting 的基础上扩展了功能,提供了一个专门的移动应用,用于处理警报、团队排班,并且可以接收任何第三方应用通过 Webhook 发送的警报。OnCall 让你能够集中所有警报,方便查看并将其路由到正确的响应团队。最后是Grafana Incident,提供了一个易于使用的事件跟踪工具,帮助你准备好所有关键的信息,便于事后活动,帮助组织专注于防止事件发生的改进。
本章将涵盖以下主要内容:
-
警觉与惊慌——如何建立优秀的事件管理
-
使用服务级指标(SLI)和服务级目标(SLO)编写优秀的警报
-
Grafana Alerting
-
Grafana OnCall
-
Grafana Incident
技术要求
在本章中,我们将深入探讨技术细节,面向如Ophelia Operator、Diego Developer和Steven Service(他们代表了运营人员、开发人员和服务交付专业人员,如在第一章中介绍的),并且可能对玛莎经理(领导层)等读者有所帮助,帮助他们了解 Grafana 的工具能做什么,以及它们如何支持已建立的事件管理。
警觉与惊慌
事故管理是许多领域中常用的过程,从火灾和医疗紧急情况等物理事故到计算机安全或服务故障。尽管在计算机领域我们可能不会处理危及生命的事故,但糟糕的事故管理流程所带来的压力是非常显著的,从焦虑和抑郁到彻底的精疲力竭,甚至可能增加心脏病和中风的风险。本节的目的是解释可观测性和 Grafana 工具如何融入事故管理策略,以及如何利用它们减少对团队的影响、缩短事故持续时间并降低事故发生的频率。在本章中,我们将进一步探讨这些概念的细节以及 Grafana 提供的支持工具。
事故管理这一主题有许多很好的公共资源可供利用;如果你愿意,可以探索以下资源:
-
紧急响应与恢复 (
www.gov.uk/government/publications/emergency-response-and-recovery): 这是英国对紧急服务提供的指南。虽然你们大多数人不会处理涉及生命或财产风险的事故,但这份文件是任何希望了解如何尽可能轻松应对事故的人的绝佳读物。 -
Atlassian 事故手册 (
www.atlassian.com/incident-management/handbook): Atlassian 事故手册是编写或审查事故管理流程时的一个极好的起点。 -
什么是事故管理? (
www.servicenow.com/uk/products/itsm/what-is-incident-management.html): 类似于Atlassian 事故手册,ServiceNow 的事故管理指南也是编写或审查事故管理流程时的一个极好的起点。 -
Google 网站可靠性工程 (
sre.google/sre-book/managing-incidents/和sre.google/workbook/incident-response/): Google 的网站可靠性工程书籍充满了有用的信息。大多数组织不会像 Google 那样以同样的规模运营服务,但这些书籍清晰地展示了如何创建一个高度可扩展的事故管理流程。
这可能看起来是对事故管理的过于简化,但我们将这些概念分为事故前、事故中和事故后。
事故前
正如口号所说,“期望最好的结果,准备最坏的情况”。在事故发生之前,知道你将如何响应事故,对于在事故发生时有效地做出反应至关重要。在本节中,我们将讨论事故发生前需要落实的各个方面。
角色和职责
事件是混乱且迅速发展的情况,不适合在此时分辨谁在做什么。你组织的事件响应角色和责任必须被清晰文档化,并且所有可能被要求响应事件的人都应理解这些责任。在事件管理方面,重新发明轮子并不可取;有几种框架可供参考,包括以下几种:
-
信息技术基础设施库(ITIL)事件管理
-
站点可靠性工程(SRE)事件管理
-
国家标准与技术研究院(NIST)事件响应框架
-
系统管理员、审计、网络和安全(SANS)事件响应框架
这些框架中有一些关键角色是共同出现的:
-
指挥官:这是有权做出决策的人员。此角色的一些关键特点如下:
-
每个事件的决策范围会有所不同,但指挥官需要能够召集正确的人,批准与客户的沟通,并处理与高级领导的内部沟通
-
这个人还掌控着整个事件的管理
-
所有其他角色都向此人汇报
-
-
沟通:这是负责内部和外部沟通的人员。以下是沟通角色的一些关键特点:
-
在事件中有效沟通对成功至关重要,这个人负责管理这一点
-
内部和第三方沟通是他们的责任
-
面向客户的沟通也是他们的责任
-
-
技术领导者:此人对于指导可能涉及到事件的许多技术人员至关重要。事件中的技术领导力的一些关键特点如下:
-
当多个团队的多人在调查一个问题时,一个人负责做出技术决策是非常重要的
-
技术领导者需要知道技术团队中的每个人在做什么,以及何时能获得最新的发现更新
-
这些框架中列出的角色非常侧重于操作(铜)层级。英国紧急服务已文档化了一种非常有效的指挥结构,金银铜,该结构概述了战术(银)和战略(金)层级的职责。在处理任何事件之前,明确高层或高级领导以及下属的责任是很有价值的。这能确保在实际事件中,所有相关人员都知道如何在需要时调动正确的领导者。我们的意思是,最好有一个可以应对造成严重损害的重大事件的计划,而不是在事件发生时才意识到需要一个。我们将更详细地探讨这些层级:
-
金色团队 – 战略职责:金色团队由高级经理或高层管理团队(C-suite)组成。金色团队的成员应始终保持关注战略层面,而不是被引入战术决策。金色团队的主要职责如下:
-
设置、审查并沟通事件管理战略
-
定义是否需要任何资源或专业技能
-
处理媒体策略
-
考虑事件可能引发的法律问题
-
在适当的情况下向股东报告
-
在银色团队的战术计划使用之前进行审批
-
事件后进行总结或事后检讨
-
-
银色团队 – 战术职责:银色团队由不同部门的经理组成。他们为铜色团队提供战术领导,做出如何执行金色团队设定的战略愿景的决策,并且在事件发生时,作为信息流动的中介,连接金色团队和铜色团队。银色团队的职责包括:
-
设置、审查并沟通事件的战术计划,上下指挥链之间
-
记录事件管理程序
-
捕捉与客户沟通应如何处理
-
选择合适的工具来管理事件
-
了解哪些团队将实现哪些战略目标
-
解决关键团队中的任何资源需求
-
在事件发生期间,向金色团队更新任何相关信息
-
-
铜色团队 – 操作职责:铜色团队负责响应事件,从初始警报到事件后的过程结束。铜色团队的职责包括以下内容:
-
承担事件的操作控制
-
当事件被声明时,通知银色团队
-
理解事件的根本原因
-
做出解决事件的决策
-
在战术计划中进行内部和外部沟通
-
完成事件后的报告和会议,处理任何持续的问题
-
在事件中减少噪音,以提高信号
无法预测事件将如何发生以及其根本原因是什么。当事件发生时,快速获取正确信息并有效沟通是两个非常重要的因素,有助于尽快从事件中恢复。
减少噪音的第一步是在可观察性系统中,这可以帮助更容易地识别重要信号。做到这一点需要了解服务,因此最好在事件发生之前就进行这一操作。以下做法可以帮助像Diego这样的工程师与像Ophelia和Steven这样的系统工程师共享其应用程序的详细领域知识:
-
确定并记录关键的 SLI(服务级指标)
-
使用分布式跟踪,这样所有调用都可以在服务图中看到
-
编写易于理解的日志消息
-
编写能够处理故障的日志,而不会产生大量信息
很多可观察性工具提供某种形式的AIOps;这些工具实际上是监控数据标准流并突出显示偏离先前数据的时间点。这不应被视为不识别关键信号的理由,因为这些工具在我们的经验中并不能替代特定领域的知识。
可能发生的第二种噪声是通信渠道的不当使用。我们当中很多人可能曾在 Slack 或 Teams 频道中看到类似现在网站宕机了吗?的消息,这些频道本应专门用于通知我们当用户计算机上发生问题时的事故。噪声和缺乏信号同样会影响客户,可能会反复通知客户每一个小的波动,或者更常见的是,在事故发生时未能通知客户。正确的沟通是事件管理策略的核心部分。常见的做法包括:
-
赋予专门的团队宣告事故及其严重性的权限。
-
在事件被宣告时自动化沟通响应——例如,更新客户可见的状态页面并在专用的内部沟通渠道中发布。
-
为事件团队建立受保护的内部沟通渠道(铜级)。
-
在事件团队与高级领导之间建立受保护的沟通渠道(铜级到银级,银级到金级)。
-
预写状态消息,以便事件团队可以为大多数消费者选择最合适的消息。
支持工具。
“工人总是把坏工作归咎于工具”这一格言在这里非常适用;没有完美的工具,一个组织有效的工具可能对另一个组织无效,市场上有许多工具。这是我们认为所有组织在其事件管理策略中应考虑的一些功能:
-
警报通知——向值班人员发送通知页面。同时,考虑使用移动应用进行非工作时间的通知。
-
流程自动化。
-
值班排班管理。
-
与其他系统的集成。
-
自动捕捉事件期间的内部沟通。
-
进行演练或模拟事故。
-
升级流程。
-
事件发生期间与客户的沟通。
现在你已经掌握了准备应对最坏情况的知识,让我们在事件发生时实际应用这些计划。
事件发生期间。
事故是不可避免的,尽管我们更希望它们不发生。在本节中,我们将讨论一些关键任务,帮助尽可能无痛地解决事件。
识别事件。
计算机系统中可以观察到许多故障模式,从即时停机故障到级联故障,再到间歇性故障。拥有清晰的信息来说明服务是否按预期正常运行,对于识别问题至关重要。这是像Diego或Ophelia这样的领域专家的责任,他们需要将这些信息写入软件服务中,或确保它们由第三方系统提供,例如计算、存储或网络服务。捕获这些信息有一些常见的方式,包括白盒监控技术和黑盒 监控技术。
白盒监控是指监控你有权限访问的系统。这种做法有助于识别服务是否健康,并提供有关服务状态的详细信息。以下是常用的几种呈现指标的方式:
-
速率、错误、持续时间(RED):这是衡量由请求驱动的服务的一种方式。速率是服务在一段时间内处理的请求量。错误是遇到错误的请求数量。持续时间是请求持续时间的分布,通常将其表示为一组百分位数或直方图。
通过这三个信号,我们可以快速将当前状态与“正常”状态进行比较,检查是否有服务接收到更多或更少的请求,是否有比平常更多的错误,或者请求的持续时间是否更长或更短。有了这些知识,事故响应团队可以识别出需要进一步调查的服务。
RED 是一个非常适合用于任何响应请求的服务系统,比如 web 服务器。
-
利用率、饱和度、错误(USE):USE 和 RED 是相辅相成的;RED 关注服务的请求,而 USE 关注服务的内部状态。利用率衡量服务处理工作所使用的资源数量(稍后我们会讨论资源)。饱和度是服务因资源不足而无法处理的工作量。错误是产生的错误数量。我们在这里使用了“资源”这个术语;不同的服务会有不同的资源,识别这些资源是领域专家的工作。常见的资源包括 CPU 和内存的可用性、网络或磁盘 I/O,甚至应用程序中可用的线程数量。
USE 最适合用于建模提供资源的服务,如存储系统或 Kubernetes 集群。
-
黄金信号:黄金信号在 Google 的 SRE 书中被引入,并且与 RED 和 USE 有很强的重叠。黄金信号包括延迟、流量、错误和饱和度。
错误和饱和度与 RED 和 USE 中描述的一样。流量是每秒请求的度量,相当于 RED 中的速率。延迟是处理请求所需的时间;这类似于 RED 中的持续时间。然而,延迟还捕捉到请求是否成功。这一信号可以区分以下两种情况:一种是持续时间较短,因为错误被迅速返回;另一种是服务需要很长时间才返回错误的更具挑战性的情况。
-
核心网页重要指标:以前对服务的视图是由后端系统驱动的。核心网页重要指标是一组从终端用户的浏览器收集的度量,通常使用真实用户监控(RUM)代理,如 Grafana Faro,它嵌入到 Web 应用程序中以收集数据。这组指标非常关注 Web 应用程序的终端用户体验。
当前的核心网页重要指标包括以下内容:
-
最大内容绘制(LCP):LCP 衡量网页的加载性能;它是衡量页面上最大元素被渲染的时间。历史上,类似的度量指标如首个内容绘制、首次有意义绘制、加载、DOMContentLoaded 和 SpeedIndex 也曾被使用;LCP 是谷歌 web.dev 团队当前的推荐指标。
-
首次输入延迟(FID):FID 衡量页面的交互性;它是从用户首次与页面互动到浏览器能够处理事件处理程序响应的时间。
-
累积布局偏移(CLS):CLS 衡量页面上渲染的内容因另一个元素被渲染而改变位置的频率。
-
与白盒监控相对,黑盒监控将服务视为一个未知的实体,并检查它是否按照终端用户所看到的行为。黑盒监控大致分为两类:
-
ping)和谷歌远程过程调用(gRPC)。市场上的其他服务也可以模拟关键用户旅程,如果需要更精细的外部监控。这种情况下,如果服务级别协议(SLA)的遵守是组织的合同义务,使用第三方合成工具是一种非常简单的方式来证明 SLA 是否被遵守。这个工具作为合成监控,是 Grafana Cloud 的一项托管服务提供的。除了 gRPC 调用,所有功能均受支持。 -
RUM使用嵌入在前端代码中的代理来收集实际终端用户使用服务的数据。虽然 RUM 提供的功能比单纯的黑盒监控更广泛,但它也可以用于根据终端用户的实际体验提供初步的警报。
黑盒监控确实存在误报的风险。虽然白盒监控仅覆盖组织控制范围内的项目,如内部网络、云服务等,黑盒监控则需要涵盖控制范围外的领域,如外部互联网提供商的网络或 DNS 服务。
通过使用常见的信号群组,并为每个服务明确这些关键的 SLI,组织可以有效地将服务健康状况的知识从领域专家传递给组织中的其他人员。详细的操作手册(通常被称为运行手册),详细说明了应对各种情况的方式,也起到了知识传递的作用。最后,一个健全的事件后处理流程有效地帮助组织摆脱了英雄文化。英雄文化是指一小部分人通过响应每一个事件来维持运转,往往以牺牲健康为代价。一个成熟的组织应从频繁的事件混乱中走向一个能够为高度积极的个体及整个组织提供成长空间的阶段。
一旦我们的监控系统通知我们出现问题,接下来的问题是谁应该参与事件处理,以及何时参与。
事件升级
如果一个事件仅需值班人员参与就能快速解决,那是理想的。遗憾的是,有些事件需要升级处理,无论是因为需要更专业的知识,还是事件的规模超出了一个人能处理的范围。每个组织都有不同的情况,因此明确的事件升级政策必须是应急计划的一部分。升级政策应提供清晰的指导,并回答以下问题:
-
当自动化系统识别到问题时,应该通知谁?
-
在工作时间和非工作时间,这个决定是否会有所不同?
-
事件的严重程度是否会影响此决定?
-
-
如果第一响应者不可用,应该通知谁?
-
如果第一响应者无法单独解决问题,应该由谁接手?
-
做出该决定时使用了哪些标准?
-
事件的持续时间?
-
事件的严重程度?
-
事件发生的时间?
-
-
事件的交接应该如何进行?
-
如果同时发生多个事件,会发生什么?
有了这些指导方针,确保所有值班人员了解政策是领导层(玛莎)的责任。特别是对于那些可能觉得需要避免打扰资深同事的初级工程师来说,这一点尤其重要。此外,还需要定期审核值班时间表,确保值班工程师不会因工作安排而过度疲劳或精疲力尽。
通信
在事件处理中,沟通至关重要。我们可以将沟通分为三个大类:
-
事件团队沟通:大多数组织使用面对面或视频会议室和聊天工具的组合。在发生事件时,有几个考虑因素需要纳入,以确保沟通顺畅:
-
通知某人加入事件的主要沟通渠道是什么?
- 聊天频道、电话/SMS 或移动应用(例如 Grafana OnCall 或 PagerDuty)
-
是否有主要的会议桥接视频会议?
- 确保在主要沟通渠道发送的任何警报中都包含详细信息
-
召集人员进入事件的预期响应时间是多少?
-
这会影响恢复时间
-
这同样会影响经常被召集参与事件的人员的健康和福祉,需要进行监控
-
-
团队沟通如何记录以便事后回顾?
-
随着事件与事后回顾之间的时间增加,人们的记忆会变得模糊。记录沟通内容是管理这一点的好方法,确保事后回顾尽可能准确。在事件发生期间使用能够简化这一过程的工具对整个事件管理过程非常有价值。
-
这里有工具和流程可以帮助。Grafana Incident 会跟踪来自 Slack 等工具的事件时间线。事件的沟通和技术负责人还应负责定期更新状态,这些更新应考虑到事后回顾。
-
-
-
内部沟通:重大事件的沟通负责人负责内部沟通。对于大多数渠道,事件的战术计划应指定更新的频率。这类沟通通常不需要详细说明;即使仅仅说“我们仍在调查问题并努力解决它”,也比保持沉默要好。内部工具发生事件时,这种沟通同样重要。
沟通负责人应向高级利益相关者(如金银团队)详细通报当前状况。由于银团队通常包括可能是事件原因的产品的技术和管理领导,这个渠道对于在需要时升级并引入专家尤为重要。遵循相同的主要沟通渠道进行事件通知是最佳实践——也就是说,如果升级是通知正确的值班人员,那么事件可以更快速地解决。然而,这也意味着需要更多工程师值班。
-
客户沟通:这可能是最重要的,因为当事件影响外部客户时,迅速发出信息向客户保证组织正在积极处理问题并恢复服务至关重要。与客户沟通的方式有很多种:
-
状态页面,可以是独立的,与组织的服务分开,也可以嵌入其中
-
邮件通知
-
社交媒体
-
短信通知
-
客户工单管理门户上的消息
在事件发生期间,通讯负责人应准备一系列预生成并已批准的客户消息,几乎不需要修改。这有助于保持信息的语气和风格正确,即使通讯负责人是在凌晨 3 点刚被叫醒的情况。也应该准备一条告知客户可能存在问题但正在调查中的消息;这种情况适用于你已经被警告有问题,但不确定是否会对客户造成实际影响。
-
在这些准备工作完成后,你将能让你的组织处于一个良好的位置,以便快速解决事件并让团队回去休息。事件发生后,可能更具挑战性的工作将开始,比如理解事件发生的原因,并沟通组织将如何解决任何潜在的根本原因。让我们探讨如何处理这一过程。
事件发生后
事件发生在大公司和小公司中;即使是那些在避免事件上非常谨慎的公司,也会经历事件。从任何事件中最重要的事情是,整个组织要了解系统中的漏洞或导致事件发生的流程缺口。
当事件发生时,寻找一个人或一个部门来归咎可能是自然的,但这种人类倾向与组织的最佳利益是直接冲突的。责备会导致繁琐的程序,缺乏创新,并最终导致组织停滞不前,因为员工停止诚实交流,转而确保自己不会被责备、降职或甚至解雇。
无责事后检讨是一个诚实且客观地审视发生了什么的空间,目的是理解事件的真正根本原因。必须假设所有员工和部门的出发点是良好的。理解无责事后检讨的目标不是消除个人或团队的责任,而是确保责任不伴随惩罚、失业或公开羞辱的恐惧。无责事后检讨的关键要素包括:
-
开放的沟通氛围,接受错误作为生活的一部分
-
鼓励诚实和接受失败
-
分享关于事件时间轴的详细信息,应该有事件期间内部沟通和系统日志的支持。
-
做出决策并寻求改进的批准
有许多指南详细介绍了这些过程,比我们在这里所讲的更为深入;我们的目标是将那些符合角色的人员引入到广泛的事件响应话题中。接下来,我们将更详细地讨论可观察性实践以及 Grafana 工具如何帮助构建一个优秀的事件响应计划的一部分。我们将从更深入地探讨 SLI 和 SLO 开始。
使用 SLI 和 SLO 编写优秀警报
SLI是用来表示当前服务水平的度量指标。一个例子可能是 15 分钟内的错误数量。
最佳实践是保持 SLI 的数量尽可能少;每个服务有三到五个 SLI 是一个不错的经验法则。这可以减少混淆,并帮助团队专注于服务的关键点。SLI 也可以被看作是一个分形概念;虽然一个服务团队可以有一个较大系统组件的指标,但整个系统也可以通过少数几个 SLI 来跟踪——例如,失败其 SLO 的服务数量。通过将跟踪的 SLI 数量保持相对较小,可以减少虚假的警报,且持续监控服务的影响保持较小。这意味着可以监控更多的服务,而无需扩展使用的工具或增加运营成本。
我们之前讨论的 RED、USE、黄金信号和核心网页重要指标模式是决定要跟踪的 SLI 时很好的参考。这些不是唯一可以作为 SLI 使用的度量标准,但它们在行业中有很好的采用率,并且被广泛理解。团队应该认真考虑是否需要使用其他的度量标准。
通过达成对 SLI 和目标的共识,编写优秀警报的过程变得更加简单,因为实施警报的人只需要考虑如何将 SLI 的业务描述(例如 15 分钟内的错误数量)转化为查询,使用 LogQL 或 PromQL,然后根据设定的目标创建阈值。以这种方式编写的警报也将容易理解。
另一个重要概念是 SLO,它指的是一个内部达成的目标,认为这是 SLI 可以接受的标准。例如,可能是 10 分钟内错误请求的比例不超过 3%。
尽管与事件警报直接无关,但有一个概念叫做错误预算,它与良好的 SLO 设置密切相关。错误预算是一个衡量其他 SLO 实现情况的 SLO。当错误预算被超过时,通常表明服务存在某种不稳定性,这应该作为一个触发器,促使团队集中精力进行修复。相反,如果错误预算较高,则可以给团队提供实验的空间,甚至有计划地停机。这也是暴露潜在问题的一个好机会,因为这些问题在未计划的故障中可能会带来灾难性的后果。这个话题在讨论 SRE 的出版物中有更详细的探讨。
SLA 是与客户或用户达成的关于服务可接受标准的协议,这些协议可能是法律协议,通常由多个 SLI 和 SLO 组成。例如,99.9% 的正常运行时间就是一个例子。通过设置 SLO 的目标,组织可以轻松地保持在合法协议的 SLA 范围内,这是确保 SLA 很少被违反并让客户信任组织的好方法。
我们已经探讨了一个良好事件响应策略的理论以及支持该策略的选择,从团队层面到组织层面。现在,让我们来看一下 Grafana 提供的三个工具来支持事件响应:Grafana 警报系统、OnCall 和 Incident。
Grafana 警报系统
Grafana 警报系统是 Grafana 的事件响应与管理(IRM)工具集中的三个主要组件之一。Grafana 警报系统本身不需要额外的授权费用,适合较小的组织使用,同时也构成了大型组织 IRM 工具的基础。
IRM 功能可以通过主 Grafana 菜单中的警报 & IRM标签访问:

图 9.1 – Grafana 警报与 IRM 主界面
Grafana 警报系统持续评估用户创建的警报规则,以判断是否存在需要警报的状态,并按照预定义的步骤将消息发送到选定的通知通道。
接下来,我们将看到如何设置警报规则,正确配置联系点和通知策略,在需要时静默警报,以及如何设置团队和团队成员。
警报规则
Grafana 警报系统的主要配置界面是警报规则界面。这个界面允许你设置新规则并查看现有规则的当前状态。学习了第四章和第五章中的 LogQL 和 PromQL 后,设置规则应该会感觉非常熟悉。
设置警报规则需要配置多个项目;让我们现在逐一讲解这些内容:
-
设置警报规则名称并定义查询和警报条件:首先,创建并命名一个查询;在我们的示例中,我们使用了以下查询,持续时间为 10 分钟:
(sum(app_frontend_requests_total{status=~ " 5.. "})/sum(app_frontend_requests_total))*100这将计算在该时间段内所有请求中已完成的百分比,状态码为
5xx,即 SLI。在3中,即 SLO。以下截图显示了可以填写这些项目的界面:

图 9.2 – 创建告警规则
-
设置告警评估行为:在设置好 SLI 和 SLO 后,我们现在需要决定如何让 Grafana 评估其下一步操作。Grafana 中告警规则可以处于三种状态:正常、待定和触发。告警评估行为管理告警规则组在各个状态之间的转换。一个评估组将按顺序评估组内每个规则,且使用相同的评估周期。在我们的例子中,我们创建了一个前端组,其中包含来自前端服务的 RED 指标。由于前端服务对业务至关重要,评估周期设置为 1 分钟,待定周期设置为 5 分钟。通过这些设置,如果我们的错误百分比超过 3,我们的规则将在 1 分钟内进入待定状态,并且如果状态持续,告警将在 5 分钟内触发。这个过程可以从下一个截图中看到。
虽然将这些值设置得尽可能低(如 10 秒)非常诱人,但这可能会带来意想不到的后果。每分钟运行查询将导致每天执行 1,440 次查询,而每 10 秒一次则会有 8,640 次查询。虽然计算能力相对便宜,但这仍然会使 Grafana 所需的资源增加六倍,并且可能带来很小的优势。另一个考虑因素是查询频率与查询周期的相互作用。如果我们每 5 分钟评估一次,但查询只看最后一分钟的数据,那么就会有未被评估的分钟,这可能会掩盖合法的间歇性错误。让我们看一下屏幕的下半部分,以管理告警规则:

图 9.3 – 管理告警规则
-
添加注解:注解用于在告警触发时将信息发送到联系人。良好的实践是包括易于阅读的摘要,捕捉关键信息,如涉及哪个服务以及问题是什么。描述应提供更多细节(如有需要),并且最佳实践是包含运行手册 URL 和仪表板链接。这些应该帮助响应者快速了解问题,并提供可跟随的补救步骤,以便他们能够迅速恢复服务。
-
配置通知:配置通知部分提供了添加标签的空间。标签可用于管理告警路由,我们将在讨论通知策略时详细介绍。点击预览路由按钮可以获取有关告警如何在当前配置下进行路由的信息。
警报菜单中的接下来的几个标签允许我们配置 Grafana 警报的其他方面。这些比主要的警报规则要小一些。让我们现在来看一看。
联系点、通知策略和静默
联系点由 Grafana 管理员配置。它们由一个名称和一个或多个集成组成。通常,联系点是负责处理问题的团队。通过一些可用的集成(例如 Webhook 和 Kafka 消息队列),建立超出简单警报的复杂联系点相对容易。在更复杂的环境中,Grafana 提供了在联系点页面上创建通知模板的选项。这些模板可以用于标准化多个联系点和集成之间的消息结构。Grafana 提供了一个很好的指南,帮助设置自定义通知:grafana.com/docs/grafana/latest/alerting/manage-notifications/template-notifications/。
来自 OpenTelemetry 演示中服务的service_name标签。相同嵌套级别的规则也可以继续匹配,这意味着服务团队和中央运维团队都可以收到通知。
静默是指在定义的时间段内不创建任何通知。它们可以用于管理使用 Grafana 警报时的维护周期。
分组和管理员
分组部分显示已分组的警报。如果数据源定义了警报但没有发送数据,Grafana 也会在这里显示警报。
管理页面以 JSON 格式提供 Alertmanager 配置;这允许管理员保存配置并将其传输到其他实例,或将其用作配置备份。
Grafana OnCall
Grafana OnCall是 IRM 的第二个主要组件,扩展了 Grafana 警报功能,新增了以下功能:
-
从多个外部监控系统接收警报通知
-
指定警报分组以减少事件中的噪声
-
指定警报组何时发送通知
-
定义值班轮换和升级路径
-
扩展通知渠道,超出 Grafana 警报中提供的内容:
-
在 ServiceNow、Jira 和 Zendesk 中创建和更新工单
-
直接通知当前值班人员
-
-
提供移动应用程序供工程师处理值班责任
Grafana OnCall 的所有功能都包含在 IRM 用户许可证中。Cloud Free 订阅包括三名用户的访问权限。Pro 和 Advanced 账户包括 5 名用户的访问权限;额外的用户在写作时按每月 $20 收费。
在接下来的部分中,我们将查看警报组以及如何设置入站和出站数据流的集成。我们还将探讨在 Grafana OnCall 中使用的模板语言以及如何管理升级链。
警报组
所有流入 Grafana OnCall 的告警都被分组到告警组中。这些组可以包含一个或多个单独的告警,分组行为由正在应用的集成模板进行管理。我们将在查看集成后讨论模板化。告警组随时可以处于以下状态之一——触发、已确认、静音或已解决。值班工程师或升级链采取的行动可以转换告警组的状态。一个告警组看起来像这样:

图 9.4 – 告警组的结构
此网页视图反映了通过集成通信渠道、移动应用、电话和短信,值班工程师可以使用的功能。告警组可以轻松地被确认、取消确认、静音或解决。如果需要召集其他团队,工程师还可以通知额外的响应者,声明事件以触发 Grafana Incident 中的流程(本章后面会讨论),或者如果它们相关,可以将告警组合并,这意味着事后清理将变得更加容易。
入站集成
用于设置入站集成或告警源的工具位于集成选项下。这些交互用于将来自外部源的告警信息发送到 Grafana OnCall。目前有超过 20 个集成,且可以使用入站 Webhook 与任何可以发送它们的系统集成。点击新建集成将开始连接到新的告警源的过程;我们将使用 Grafana 告警作为我们的源,因为我们刚刚已经了解过它。首先,为集成命名并描述,然后选择告警管理器和联系点。Grafana OnCall 能与任何兼容 Prometheus 的告警管理器集成;Grafana Cloud 中配置了一个默认告警管理器,名为Grafana。最后,点击创建集成,您将看到以下界面:

图 9.5 – Grafana 告警集成
HTTP 端点用于配置告警源以发送告警。如果您在配置特定集成时需要帮助,如何连接链接提供了更多信息。要测试集成,发送演示告警将创建一个测试告警。
分组 ID字段来自payload.groupKey字段的值。同样,如果payload.status为resolved,告警组将被解决。这意味着告警源也可以发送解决更新。
接下来的部分,Web、电话、Slack、Telegram、电子邮件和MS Teams,包含了如何将告警组的通知发送到这些 ChatOps 集成的模板。
添加路由允许你根据每个警报组的 Jinja 路由模板选择一个升级链,这些警报组源自集成。这是通过点击 添加路由 按钮实现的。路由还包括将消息发布到任何已配置的 ChatOps 集成的选项。
另一个在集成页面上的三点菜单中提供的重要功能是启动维护期。维护可以是调试模式,这会静音所有升级,或者是标准维护模式,将所有警报收集到一个警报组中。
接下来我们来讲解模板和升级链。
模板
Jinja 是一种模板语言,具有许多有用的功能,可以解析警报组中的多个警报,使得值班人员能快速看到发送给他们的信息中的重要内容。以下是该语言的一些特性和语法:
-
循环: 循环的语法如下:
{% for item in seq -%} Do something with item from seq {% else %} Do something else if there are no items in seq {%- endfor %} {"results": [{"metric": "bigbadwolf", "value": 1},{"metric": "littlepiggies", "value": 3},{"metric": "houses", "value": 1}]}然后我们可以使用以下 Jinja 模板:
*Values:* {% for item in results-%} {{ item['metric'] }}: '{{ item['value'] -}}'{{ "\n" }} {%- endfor %}这将产生以下输出:
*Values:* bigbadwolf: '1' littlepiggies: '3' houses: '1' -
条件: 条件可以使用此语法构建:
{% if field == condition1 %} Do something {% elif field == condition2 %} Do something different {% else %} Do something else if condition 1 and 2 didn't match {% endif %} -
时间: 当前时间 -
tojson_pretty: 美化的 JSON -
iso8601_to_time: 将时间从iso8601格式(2015-02-17T18:30:20.000Z)转换为日期时间格式 -
日期时间格式: 将时间从日期时间格式转换为给定的格式(默认%H:%M/%d-%m-%Y) -
regex_replace: 执行正则查找和替换 -
regex_match: 执行正则匹配,并返回True或False -
b64decode: 执行 Base64 字符串解码 -
-) 添加到块的开始或结束,以去除其前后的所有空白字符。如果seq = [1,2,3,4,5,6,7,8,9],我们可以按如下方式书写:{% for item in seq -%} {{ item }} {%- endfor %} 123456789如果没有这个空白字符管理,它将呈现如下:
1 2 …Jinja 还提供了修剪功能,可以去除空白字符。如果你想保持空白字符,可以添加加号 (
+),表示应保留空白。
有关 Jinja 的更多信息,请访问网站: https://jinja.palletsprojects.com。
现在我们了解了如何使用模板来格式化负载和消息,让我们来看看升级链。
升级链
升级链 允许我们为警报组设置标准工作流。这对于根据警报的严重性或内容、时间或其他因素来路由警报非常有用。可以设置多个步骤:
-
等待: 等待指定的时间后,继续到下一步。 -
通知用户: 向一个用户或一组用户发送通知。 -
通知值班表上的用户: 向值班表中的某个用户或用户组发送通知。 -
自动解决事件: 立即以状态自动解决解决警报组。 -
通知整个 Slack 频道: 向整个 Slack 频道发送通知。 -
通知 Slack 用户组: 向 Slack 用户组发送通知。 -
触发外发 webhook: 触发一个外发的 webhook。 -
逐个通知用户(轮询):每条通知将按照顺序依次发送给一组用户,采用轮询的方式。 -
如果当前时间在范围内,则继续升级:只有当前时间处于指定范围内时,才会继续升级。这可以用于在非工作时间暂停升级。 -
如果每 Y 分钟 >X 个警报,则继续升级(测试版):仅在超过某个阈值时继续升级。 -
从头开始重复升级(最多 5 次):循环升级链。
当通知通过值班排班或轮询直接发送给用户时,将遵循用户的个人通知步骤。这些可以由用户进行管理。用户页面会突出显示所有用户的通知步骤状态;任何没有配置通知的用户将标记为警告。
外发集成
Grafana OnCall 提供了几种执行外部集成的方法,这些方法涉及集成外部工具,以便可以发送外发消息,无论是发送到消息工具还是任何可以接收 webhook 的系统。这些集成有两种类型:
-
ChatOps,它是包括 Slack、Telegram 和 MS Teams 在内的集成。这些可以通过设置 | ChatOps进行配置。
-
Webhooks:这些外发 Webhooks 提供与任何可以接收它们的系统集成的能力,并且它们是由 OnCall 中的事件触发的。
以下截图展示了如何在 Grafana OnCall 中设置 webhook:

图 9.6 – 配置外发 webhook
Webhooks 可以通过升级步骤触发,或者当警报组被创建或过渡到特定状态时触发。
排班
排班是 Grafana OnCall 管理各团队值班人员的方式。这些非常容易设置,并且可以为你提供标准轮班排班的能力,同时还可以设置任何覆盖规则。排班还会通知 Slack 频道当前的值班班次以及任何未分配的班次。新排班屏幕在以下截图中展示:

图 9.7 – 设置新排班
现在,让我们来看一下 Grafana 事件。
Grafana 事件
Grafana IRM 提供的最后一个重要组件是事件。该工具帮助简化和自动化事件管理战术计划的许多方面。该工具与组织的聊天工具(如 Slack)集成,提供团队成员在该工具中声明事件的能力。
一旦事件被声明,Grafana Incident 可以自动启动视频会议、更新状态页面工具、从 GitHub 向事件时间轴添加上下文等,具体取决于已配置的集成。事件的团队成员可以指定每个人在事件中的角色,并在事件期间指定和分配任务。随着事件的发展,Grafana Incident 将记录重要信息到时间轴中,这些信息可以发布,并在定期的事件后回顾中轻松审查。
要开始在 Grafana Cloud 中使用 Grafana Incident,管理员需要首先同意进行一些集成的设置。同时,最好与消息工具(如 Slack)和视频会议工具(如 Zoom)进行集成,因为 Grafana Incident 在事件声明时会使用这些工具。在视频会议中会创建一个新的事件桥接,工具还可以在指示时记录聊天消息,以便在事件后进行回顾。如果适用,还应配置与 Statuspage、GitHub 和 Jira 的集成;这些集成分别可以更新 Statuspage、记录拉取请求和问题的状态,以及管理 bug 工单。随着工具的成熟,我们预计可用的集成列表将会扩展。
让我们来看看 Grafana Incident 在事件发生时如何使用:
-
事件发生期间:在事件发生期间,可以指定一名指挥官和多名调查员。可以将预定义的标签与事件关联,并设置事件的严重性。调查员随后可以在事件时间轴中记录文本更新,以及相关的查询、警报和访问的面板。工具将收集所有相关的聊天记录、文本更新、执行的查询、触发的警报和使用的面板。调查员还可以触发已配置的外部 Webhook。事件界面包括任务列表,还可以附加指向相关资源的链接。
-
事件发生后:在事件发生后,收集到的信息会被整理成事件的时间轴。该事件的时间轴可以被进一步审查。Grafana Incident 还会整理标准指标,这些指标可以在 Insights 页面上以更高的层级查看。
Insights 页面默认显示过去 90 天内所有事件的高层次指标。最佳实践是组织中的银级领导团队应定期审查此页面,并作为正式过程的一部分向金级团队汇报。这有助于确保事件得到妥善处理,团队安排了修复工作,从而减少事件对组织的频率和影响。
Grafana 提供了多个 AI 和 机器学习(ML)工具来帮助事件管理:
-
Suggestbot:此工具使用 自然语言处理(NLP)分析事件期间的对话,并建议与正在讨论的主题相关的仪表盘。
-
OpenAI 集成:这是目前正在公开预览的工具。其目的是加速编写事件后总结的繁琐过程。该工具使用 OpenAI 的 ChatGPT 将事件时间线提炼成一个摘要,并可以进一步微调。使用此集成需要 OpenAI 账户。此集成可以生成以下内容:
-
事件的简要描述
-
事件发生前的时间线
-
解决事件所采取的措施的详细信息
-
-
ML 预测:这个工具将基于过去状态的学习模型预测度量指标的未来状态。此功能仅适用于度量数据(来自 Prometheus、Graphite 或 Loki 的度量查询)。这些预测可以用于仪表板或驱动警报。
-
ML 异常检测:这个工具为度量数据构建了一个“正常”状态的模型,当度量数据超出正常范围时,会突出显示这些异常值。这些异常值可以用于警报触发。
-
ML Sift:Sift 也是一款公开预览工具。这是一款强大的事件管理工具,它将从基础设施的遥测数据中提取信息,帮助识别那些可能被事件的噪声掩盖的关键细节。Sift 将查找以下内容:
-
错误日志中的模式
-
Kubernetes 集群中的崩溃
-
噪声较大的 Kubernetes 节点,负载较高
-
有资源限制的容器
-
最近发生的部署
-
Tempo 中看到的慢请求
-
现在,你应该已经有信心使用 Grafana 提供的工具为事件做好准备并做出响应。
总结
在这一章中,我们已经了解了如何建立一个优秀的事件管理流程,这将帮助你评估并改进你组织中的相关流程。我们还探讨了 SLI、SLO 和 SLA 及其使用方法,通过这些工具,你可以迅速判断服务是否响应成功。你已经掌握了选择合适 SLI 的技巧,这使你能够透明地与组织中的其他成员分享你负责的服务是否按预期运行。反过来,这种透明度帮助组织快速识别问题所在,并将资源集中用于解决问题。
最后,我们查看了 Grafana 提供的事件管理工具,了解了如何配置和使用它们来支持优秀的事件管理流程。
下一章将探讨我们如何使用 Grafana 和 OpenTelemetry 提供的工具,自动化收集、存储和可视化数据的过程,以便在可观察性平台中使用。
第十章:使用基础设施即代码进行自动化
本章将探讨如何使用基础设施即代码(IaC)工具来自动化管理 Grafana 可观察性平台的各个组成部分。我们将重点介绍Ansible、Terraform和Helm,这些工具可以帮助团队以可重复和自动化的方式管理其系统的多个方面。本章将平台分为收集和处理层、存储层和可视化层,并概述如何自动化每个组件。本章将提供技术工具来创建一个易于管理且高度可扩展的可观察性平台,并结合第十一章中的信息,你将能够引领你的组织轻松地利用可观察性的强大功能。
本章将涵盖以下主要内容:
-
自动化 Grafana 的好处
-
介绍可观察性系统的组成部分
-
使用 Helm 或 Ansible 自动化收集基础设施
-
掌握 Grafana API
-
使用 Terraform 或 Ansible 管理仪表盘和警报
技术要求
本章涉及使用 Ansible、Terraform 和 Helm,建议在开始阅读之前先安装它们。本章还将讨论几个你应该至少有所了解的概念:
-
Kubernetes 对象
-
Kubernetes 操作员模式
自动化 Grafana 的好处
可观察性工具结合了来自许多应用程序、基础设施服务和其他系统组件的遥测数据的收集、存储和可视化。自动化为我们提供了一种可测试、可重复的方式来满足这些需求。使用 Helm、Ansible 和 Terraform 等行业标准工具有助于我们长期维护这些系统。使用自动化有很多好处,包括以下几点:
-
它减少了与手动流程相关的风险。
-
领域专家可以为开发人员交互的系统提供自动化服务。这使得开发团队有信心正确使用这些不熟悉的系统。这些知识的形式如下:
-
遥测数据架构
-
可重复的系统架构
-
数据可视化管理的最佳实践
-
-
通过提供自动化,领域专家能够通过让团队使用更简单、更易用的系统自助服务,从而专注于更高价值的工作。
-
它提供了一条黄金路径,使得开发团队能够轻松、快速地采用可观察性,并能将更多时间专注于增值活动。
-
它使最佳实践和运营流程的扩展变得更加容易。这对于正在增长的组织尤为重要,因为一个可能适用于少数团队的流程无法扩展到数十个团队。
-
它确保成本信息始终可以追溯。
现在我们已经介绍了为什么你想使用自动化,接下来让我们看看构成可观察性平台的组件,这样我们就能轻松地自动化系统的不同方面。
介绍可观察性系统的组件
可观察性系统包含许多组件,涉及数据的生产、消费、转换、存储和使用。在本章中,我们将把这些组件分成四个不同的系统,以便明确我们在讨论可观察性平台的哪个方面。自动化的不同方面将吸引不同的受众。我们将讨论的系统如下:
-
数据生产系统:这些是生成数据的系统。应用程序、基础设施,甚至数据收集系统的组件都会产生数据。我们来看看其关键特性:
-
这些系统由开发人员如Diego或运营专家如Ophelia管理(有关这些角色的详细信息,请参见第一章)。
-
这些系统作为应用程序或组件测试过程的一部分进行测试。如果使用数据模式,则可以通过诸如 JSON 模式之类的工具进行验证。
-
-
数据收集系统:这些系统收集由数据生产系统生成的日志、度量和跟踪。它们通常提供用于转换数据的工具。它们的关键特性如下:
-
这些系统通常由专业的运营团队、可观察性工程师、站点可靠性工程师或平台工程师管理。
-
这些系统是配置的基础设施。
-
自动化涉及使用基础设施即代码(IaC)工具和静态分析工具(如可用)来验证基础设施。
-
-
数据存储系统:这些是用于存储数据并使其可搜索的系统。如果你的可观察性平台利用了 SaaS 工具,那么这些系统将由你的供应商提供。Loki、Prometheus、Mimir 和 Tempo 都是存储系统的例子。这些系统的一些重要特性包括:
-
这些系统通常由专门的第三方管理,但当它们在组织内部管理时,通常会由与数据收集系统相同的团队管理。
-
这些系统是配置的基础设施。
-
自动化涉及使用 IaC 来配置本地资源,或者利用 SaaS 工具,如使用 Grafana Labs 与 IaC 配置。
-
-
数据可视化系统:这些是允许用户搜索存储在存储系统中的数据,并生成可视化、警报和其他理解数据的方法的系统。Grafana 是一个可视化系统的例子。以下是此类系统的一些重要特性:
-
这一层的管理通常是共享责任。管理特定系统的开发人员和运维人员应该被授权负责他们的仪表盘。管理数据收集和存储层的团队通常是赋能整个组织的团队。
-
这些系统是预配置的基础设施。
-
自动化涉及使用基础设施即代码(IaC)来预配置本地资源,或者利用像 Grafana Labs 这样的 SaaS 工具,结合 IaC 配置。
-
在本章中,我们将讨论前面列表中的系统 2、系统 3 和 系统 4。虽然系统 1很重要,但它是一个非常广泛的领域,且自动化策略对于不同类型的数据生产者有所不同。然而,在大多数情况下,团队可以依赖他们所使用的库进行的测试,或者他们运行的第三方系统。
让我们先来看看如何使用 Terraform 或 Ansible 来部署数据收集系统。
使用 Helm 或 Ansible 自动化收集基础设施
自动化安装用于收集遥测数据的基础设施是构建一个优秀可观察性平台的关键部分。支持这些功能的工具取决于你部署的基础设施。在这一部分,我们将通过以下工具来研究如何安装OpenTelemetry Collector和Grafana Agent:
-
Helm 是一个用于打包和管理 Kubernetes 应用程序的工具。Helm 图表包含了应用程序所需的各种 Kubernetes 组件的所有配置文件,通常处理应用程序的变量设置。我们将在 Kubernetes 环境中使用 Helm。
-
Ansible 是一个将操作标准化为可重复执行的剧本的工具。它使用简单的 YAML 配置文件来定义需要执行的操作,并利用 OpenSSH 连接到目标服务器以执行操作。我们将在虚拟或裸机环境中使用 Ansible,但它也可以用来管理 Kubernetes 环境。
重要提示
OpenTelemetry 和 Grafana 都提供了 Kubernetes 操作符,可以通过 Helm 安装。我们也会概述这些工具。
现在让我们看看如何使用 Helm 和 Ansible 来自动化安装 OpenTelemetry Collector 和 Grafana Agent。
自动化安装 OpenTelemetry Collector
在本书中,我们一直使用 OpenTelemetry Collector 从 OpenTelemetry 演示应用程序收集数据并将其发送到我们的 Grafana 实例。首先,我们将使用已经部署的配置,探索使用 OpenTelemetry 提供的 Helm 图表将 Collector 部署到 Kubernetes 集群中。
OpenTelemetry Collector Helm 图表
我们首先在第三章安装了 OpenTelemetry Helm 图表,然后在第四章、第五章和第六章中更新了配置。OpenTelemetry 在其 Git 仓库中提供了关于可用配置选项的详细信息,地址为 https://github.com/open-telemetry/opentelemetry-helm-charts/tree/main/charts/opentelemetry-collector。
让我们看看我们在第六章中应用的最终配置,看看我们是如何配置 OTEL Helm 图表的。你可以在 Git 仓库中的/chapter6/OTEL-Collector.yaml文件中找到它。
我们将首先查看的配置块是mode,它描述了收集器将在 Kubernetes 中如何部署。可用的选项有deployment、daemonset和statefulset。在这里,我们使用deployment选项:
mode: deployment
让我们详细探索一下可用选项:
-
deployment会以固定数量的 Pod 进行部署,这就是 Kubernetes 中的replicaCount。在我们的参考系统中,我们使用了这种模式,因为我们知道系统将部署到单节点 Kubernetes 集群,并且它允许我们将通常在多节点集群中独立使用的预设组合起来。 -
一个
daemonset会与一个收集器一起部署到集群中的每个节点。 -
statefulset会以独特的网络接口和一致的部署进行部署。
我们在讨论架构时会在第十一章中讨论如何选择适当的模式。这些部署模式也可以组合在一起,以在 Kubernetes 集群中提供特定功能。
接下来我们将查看的配置块是presets:
presets:
logsCollection:
enabled: true
includeCollectorLogs: false
kubernetesAttributes:
enabled: true
kubernetesEvents:
enabled: true
clusterMetrics:
enabled: true
kubeletMetrics:
enabled: true
hostMetrics:
enabled: true
如你所见,这个配置只涉及启用或禁用不同的功能。让我们详细看看这些参数:
-
logsCollection参数告诉收集器从 Kubernetes 容器的标准输出收集日志。我们没有包括收集器日志,因为这可能会导致日志级联现象,即收集器读取它自己的日志输出并将收集的日志写入该输出,然后再读取。这种设置下,建议仅在daemonset模式下使用logsCollection参数。 -
kubernetesAttributes参数会在收集器接收日志、指标和追踪数据时收集 Kubernetes 元数据。这包括如k8s.pod.name、k8s.namespace.name和k8s.node.name等信息。属性收集器在所有模式中都是安全使用的。 -
kubernetesEvents参数会收集集群中发生的事件,并将它们发布到日志管道中。实际上,集群中发生的每个事件都会在 Loki 中收到一条日志条目,使用此配置。集群事件包括 Pod 创建和删除等。最佳实践是在deployment或statefulset模式下使用kubernetesEvents,以避免事件的重复。 -
三个指标选项会收集关于系统的指标:
-
clusterMetrics查看整个集群。应该在deployment或statefulset模式下使用。 -
kubeletMetrics收集来自 kubelet 的有关节点、Pod 和容器的指标。应在daemonset模式下使用。 -
hostMetrics直接从主机收集数据,例如 CPU、内存和磁盘使用情况。应在daemonset模式下使用。
-
我们将跳过一些标准的 Kubernetes 配置块,接下来考虑 config 块。config 块有几个子块:
-
遥测管道包括以下内容:
-
receivers:接收器位于管道的开始部分。它们接收数据并进行转换,将数据添加到管道中,供其他组件使用。 -
processors:处理器用于管道中执行各种功能。有支持的处理器和贡献的处理器可供使用。 -
exporters:出口器位于管道的末端。它们接收以内部管道格式传递的数据,并进行转换以将数据发送到下一阶段。 -
connectors:这些将receivers和exporters结合起来,连接管道。connectors充当exporters,将数据从一个管道发送到下一个管道,同时充当receivers,接收数据并将其添加到另一个管道中。
-
-
与管道分开的是
extensions,它们为收集器添加额外的功能,但不需要访问管道中的遥测数据。 -
最后,还有一个
service块,用于定义正在使用的管道和扩展。
我们在 config 块中使用的唯一扩展是 health_check 扩展:
config:
extensions:
health_check:
check_collector_pipeline:
enabled: false
这启用了一个端点,可用于 Kubernetes 集群中的存活性和/或就绪性探针。这对你来说非常有用,可以轻松查看收集器是否按预期工作。
在我们的 receivers 块中,我们配置了两个接收器:otlp 和 prometheus:
config:
receivers:
otlp:
protocols:
http:
endpoint: 127.0.0.1:4318
cors:
allowed_origins:
- "http://*"
- "https://*"
prometheus:
config:
scrape_configs:
- job_name: 'opentelemetry-collector'
tls_config:
insecure_skip_verify: true
scrape_interval: 10s
scrape_timeout: 2s
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $$1:$$2
让我们更仔细地看看这些接收器:
-
OTLP接收器配置我们的收集器实例,在 Kubernetes 节点的127.0.0.1上暴露4318端口,这使得演示应用程序能够轻松地提交遥测数据。 -
Prometheus接收器用于收集来自收集器本身的指标。此接收器配置显示了一个重新标记的示例,我们将meta_kuberentes_pod_annotation_prometheus_io_port重新命名为__address__,这是 OTLP 中使用的标准。
在我们的配置中,我们设置了 k8sattributes、resource 和 attributes 处理器。k8sattributes 处理器从 kubelet 中提取属性,并将其添加到管道中的遥测数据中。resource 和 attributes 处理器分别插入或修改资源或属性。我们不会详细讨论这些概念,但资源用于标识生产遥测数据的源。
在我们的配置中,我们使用了 spanmetrics 和 servicegraph 两个连接器:
config:
connectors:
spanmetrics:
dimensions:
- name: http.method
default: GET
- name: http.status_code
namespace: traces.spanmetrics
servicegraph:
latency_histogram_buckets: [1,2,3,4,5]
两个connectors用于从traces管道导出数据并将其接收在metrics管道中。spanmetrics收集servicegraph生成的度量,这些度量描述了服务之间的关系,这些度量使得服务图能够在 Tempo 中显示。
我们config块中的最后一个子块是services。这个子块定义了要加载的扩展和管道的配置。每个管道(logs、metrics和traces)定义了使用的receivers、processors和exporters。让我们来看一下metrics管道,因为它是最复杂的:
metrics:
receivers:
- otlp
- spanmetrics
- servicegraph
processors:
- memory_limiter
- filter/ottl
- transform
- batch
exporters:
- prometheusremotewrite
- logging
如前所述,receivers 是OTLP、spanmetrics和servicegraph。我们接着指示管道按照列出的顺序使用memory_limiter、filter、transform和batch处理器。你可能会注意到我们的过滤器命名为ottl,采用processor/name的语法,这在需要使用相同的处理器并配置不同参数时非常有用。最后,管道使用prometheusremotewrite的 exporters 并通过日志输出数据。
你可能已经注意到,/chapter6/OTEL-Collector.yaml文件中没有定义 exporters——这是因为它们在/OTEL-Creds.yaml中定义,这也突显了 Helm 的一个非常有用的功能,即能够根据功能分离配置文件。当我们安装 Helm chart 时,我们使用类似下面的命令:
helm install owg open-telemetry/opentelemetry-collector --values chapter3/OTEL-Collector.yaml --values OTEL-Creds.yaml
-f 或 --values 选项可以对多个 YAML 文件使用多次——如果存在冲突,则始终优先使用最后一个文件。通过这种方式结构化 YAML 文件,我们可以将完整配置拆分成不同部分,以保护敏感信息(如 API 密钥),同时仍然使主配置易于访问。我们还可以将此功能用于其他目的,比如在测试环境中覆盖默认配置。这里需要小心优先级问题,因为重复的数组不会合并。以这种方式部署 collector 在很多情况下非常棒。然而,它有一个限制——每当配置发生变化,或需要安装新版本的 collector 时,都需要进行 Helm 的install或upgrade操作。这就需要一个了解并可以访问每个集群的系统,才能部署 collector,这可能会带来瓶颈和安全风险。让我们来看看 OpenTelemetry 操作符,它提供了解决这些问题的方法。
OpenTelemetry Kubernetes 操作符
OpenTelemetry 还提供了一个 Kubernetes 操作符来管理 OpenTelemetry Collector,并允许对工作负载进行自动化仪器化。这个操作符仍在积极开发中,预计功能集会增加。
Kubernetes Operator 使用 自定义资源定义(CRDs)为 Kubernetes API 提供扩展,这些扩展被 Operator 用来管理系统。使用 Operator 的优势包括以下几点:
-
管理 OpenTelemetry Operator 或自动化仪器化系统所涉及的复杂逻辑可以由 OpenTelemetry 项目中的专家设计。对于负责管理 OpenTelemetry 安装的人来说,Operator 提供了一个定义好的 CRD 规范,可以用来在 CI/CD 管道中验证提议的配置。
-
OpenTelemetry Operator 还允许有限的自动化升级。由于可能会有破坏性变更,次要和主要版本的更新仍需要通过 Helm 升级来应用。
-
它可以与 GitOps 工具结合使用,将解决方案从一个必须知道每个集群并具有必要凭证来部署到这些集群的中央系统,转变为一个每个集群从中央版本控制的仓库中读取所需配置的解决方案。
-
当涉及到通过添加注解使 OpenTelemetry 自动仪器化更容易被应用程序访问时,Operator 真正表现出色。对于大多数使用场景,自动仪器化将提供充足的度量和追踪遥测,以便了解应用程序。
OpenTelemetry Collector 也可以安装在虚拟机或裸金属服务器上,这个过程可以通过如 Ansible 之类的工具来自动化。让我们来看看如何处理这个问题。
OpenTelemetry 和 Ansible
OpenTelemetry 不提供 Ansible 的官方集合。它分别为 Alpine、Debian 和 Red Hat 系统提供打包版本的 Collector,格式为 .apk、.deb 和 .rpm 文件。使用 community.general.apk、ansible.builtin.apt 或 ansible.builtin.yum,可以用类似以下配置的方式安装此包:
- name: Install OpenTelemetry Collector
ansible.builtin.apt:
deb: https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.85.0/otelcol_0.85.0_linux_amd64.deb
安装好软件包后,配置收集器所需做的唯一其他事情是应用配置文件。默认配置文件位于 /etc/otelcol/config.yaml,并在 systemd 启动收集器时使用。Ansible 可以覆盖此文件或直接修改它。可以使用以下配置来完成这项工作:
- name: Copy OpenTelemetry Collector Configuration
ansible.builtin.copy:
src: /srv/myfiles/OTEL-Collector.yaml
dest: /etc/otelcol/config.yaml
owner: root
group: root
mode: '0644'
在本书中,我们已经多次讨论了 OpenTelemetry 代理。这样做的一个主要原因是,OpenTelemetry 还提供了我们用来生成真实样本数据的 Demo 应用程序。接下来,让我们来看看 Grafana Agent。
自动化安装 Grafana Agent
Grafana 生产了自己的代理,Grafana 推荐在其云平台中使用这个代理。Grafana Agent 还提供自动化选项,我们将在本节中介绍这些选项。
Grafana Agent Helm charts
Grafana 提供了两个 Helm 图表,grafana-agent 图表和配置选项,请查看 Helm 图表文档 github.com/grafana/agent/tree/main/operations/helm/charts/grafana-agent。类似地,agent-operator 图表的文档可以在 github.com/grafana/helm-charts/tree/main/charts/agent-operator#upgrading-an-existing-release-to-a-new-major-version 找到。可用的 CRD 详细信息可以在操作员架构文档中找到 github.com/grafana/agent/blob/v0.36.2/docs/sources/operator/architecture.md。
Grafana Agent 和 Ansible
与 OpenTelemetry 不同,Grafana 维护着一个 Ansible 集合(docs.ansible.com/ansible/latest/collections/grafana/grafana),其中包含管理收集、存储和可视化系统的工具,我们将在后续章节中重新访问它。
包含的 grafana_agent 角色用于管理数据收集,并将代理安装在 Red Hat、Ubuntu、Debian、CentOS 和 Fedora 发行版上。此角色可以按如下方式使用:
- name: Install Grafana Agent
ansible.builtin.include_role:
name: grafana_agent
vars:
grafana_agent_logs_config:
<CONFIG>
grafana_agent_metrics_config:
<CONFIG>
grafana_agent_traces_config:
<CONFIG>
日志、指标和追踪的配置特定于该遥测类型,Grafana 提供的文档涵盖了使用该配置来管理代理的内容。
熟悉 Grafana API
Grafana 提供了一个功能齐全的 API,适用于 Grafana Cloud 和 Grafana 本身。这个 API 与前端使用的相同,这意味着我们也可以通过直接的 API 调用或使用类似 Terraform 的 IaC 工具来操作 Grafana 的功能。我们将首先对 Grafana Cloud 和 Grafana 中可用的 API 进行高层次的了解,然后我们将研究 Grafana 的 Terraform 模块和 Ansible 集合,看看如何使用它们来管理 Grafana Cloud 实例。
探索 Grafana Cloud API
Grafana Cloud API 用于管理 Grafana Cloud SaaS 安装的各个方面。让我们高层次地了解一下 Grafana Cloud API 提供的功能:
-
accessPolicyId,即访问策略对象的唯一 ID。 -
堆栈:这些端点管理 Grafana Cloud 堆栈。以下是它们的主要功能:
-
堆栈的创建、读取、更新和删除功能
-
重新启动特定堆栈上的 Grafana
-
列出特定堆栈上的数据源
-
-
Grafana 插件:这些端点管理与堆栈相关的 Grafana 实例上安装的插件。它们的功能包括创建、读取、更新和删除安装在特定堆栈上的 Grafana 插件的功能。
-
区域:这些 API 端点列出了可用的 Grafana Cloud 区域。它们用于读取可以用来托管堆栈的可用 Grafana Cloud 区域的功能。
-
API 密钥:这些端点用于管理云 API 密钥,其主要功能是创建、读取和删除 API 密钥。这些端点现已弃用,因为 Grafana 已转向使用基于访问策略和令牌的认证技术。API 密钥端点将在未来的更新中被移除。
我们将在 第十一章 中更详细地讨论访问策略和令牌,其中我们会讨论 访问级别,作为构建一个优秀可观察性平台的一部分。所有 Grafana Cloud 端点都有一个关联的访问策略,且所使用的令牌必须获得该策略的授权才能成功响应。
更详细的信息可以在 Grafana 的文档中找到,网址为 https://grafana.com/docs/grafana-cloud/developer-resources/api-reference/cloud-api/,其中包括请求中所需的参数和详细信息,以及示例请求和响应。
我们现在已经回顾了 API 端点。接下来,我们将讨论 Grafana 提供的 Terraform 提供者和 Ansible 集合,这些工具可以用于通过基础设施即代码(IaC)自动化与上述 API 进行交互。
使用 Terraform 和 Ansible 管理 Grafana Cloud
Grafana 提供了 Terraform 提供者和 Ansible 集合,用于管理组织的云实例。让我们来探讨如何利用这些工具通过 Grafana Cloud API 来管理 Grafana Cloud 实例。
Grafana Terraform 提供者
Grafana Terraform 提供者具有与我们讨论过的云 API 端点相对应的资源。该提供者还提供用于其他 Grafana API 端点的资源,我们将在本章后面讨论管理仪表板和警报时介绍这些资源。该提供者的官方文档可以在 Terraform Registry 上找到,网址为 registry.terraform.io/providers/grafana/grafana/latest/docs。
重要提示
本章是基于 Grafana Terraform 提供者的 2.6.1 版本编写的。
以下是一些常用的 Terraform 资源,并附有使用示例:
-
首先,让我们看一下如何使用提供者。
grafana_cloud_stack数据提供者用于查找一个名为acme-preprod的堆栈,我们稍后将使用它来指定我们的访问策略创建位置:data "grafana_cloud_stack" "preprod" { slug = "acme-preprod" } -
grafana_cloud_access_policy资源允许我们创建一个访问策略。在这里,我们将region值设置为us,并指定名称和显示名称。最后,我们指定策略的作用范围——在这种情况下,我们希望能够写入日志、指标和追踪。然后,我们之前找到的stackID 将用于指定在哪里创建此访问策略:resource "grafana_cloud_access_policy" "collector-write" { region = "us" name = "collector-write" display_name = "Collector write policy" scopes = ["logs:write", "metrics:write", "traces:write"] realm { type = "stack" identifier = data.grafana_cloud_stack.preprod.id } } -
最后,
grafana_cloud_access_policy_token资源可用于创建一个新的令牌。我们指定区域、要使用的访问策略和名称。然后,令牌可以通过grafana_cloud_access_policy_token.collector-token.token读取:resource "grafana_cloud_access_policy_token" "collector-token" { region = "us" access_policy_id = grafana_cloud_access_policy.collector-write.policy_id name = "preprod-collector-write" display_name = "Preprod Collector Token" expires_at = "2023-01-01T00:00:00Z" }
这不是我们使用 Grafana Terraform 提供者能做的唯一事情:当我们讨论管理仪表盘和警报时,本章稍后会考虑另一个示例。通常,这会与另一个提供者结合使用,将新创建的令牌记录在秘密管理工具中,例如 AWS Secrets Manager 或 HashiCorp Vault,以便在部署收集器时可以访问。
让我们看看如何使用 Grafana 提供的另一个 IaC 工具——Grafana Ansible 集合来管理 Grafana Cloud 系统。
Grafana Ansible 集合
Grafana Ansible 集合的功能不如 Terraform 提供者那样丰富,尤其是在管理云实例时。然而,可以通过 Ansible URI 模块访问许多来自 Grafana Cloud API 的功能。官方集合文档可以在 Ansible 网站上找到,链接为:docs.ansible.com/ansible/latest/collections/grafana/grafana/。社区提供的集合也可用,但在此不做讨论。相关文档请参见:docs.ansible.com/ansible/latest/collections/community/grafana/index.html。
重要提示
本章是在 Grafana Ansible 集合的 2.2.3 版本下编写的。
我们将通过 Ansible 管理 Grafana Cloud 堆栈。name 和 stack_slug(这是我们正在交互的堆栈)值按照惯例被设置为相同的字符串。然后我们需要设置堆栈的 region 值,以及使用 org_slug 设置堆栈将属于的组织:
- name: Create preprod stack
grafana.grafana.cloud_stack:
name: acme-preprod
stack_slug: acme-preprod
cloud_api_key: "{{ grafana_cloud_api_key }}"
region: us
org_slug: acme
state: present
到目前为止,我们已经看过了 Grafana Cloud 的 API。这个 API 非常适合管理 Grafana Cloud 中的可观察性平台,但许多团队可能更关注在 Grafana UI 中管理仪表盘、警报和其他项目。Grafana 还提供了一个 API 来管理 Grafana UI 中的对象——让我们现在来看看。
探索 Grafana API
虽然 Grafana Cloud API 仅用于管理 Grafana Cloud SaaS 实例,但 Grafana API 的覆盖面非常广泛,因为 Grafana 有很多功能。这些 API 可以用于 Grafana Cloud 和本地安装的 Grafana 实例。
与 Grafana Cloud API 类似,所有端点都使用基于角色的访问控制。然而,Grafana API 提供了额外的认证选项:服务帐户。服务帐户应该用于任何需要与 Grafana 交互的应用程序。
由于大多数团队会频繁使用一小部分 API,因此我们这里只讨论一些常见的 API。然而,还有很多其他 API 可以用来自动化管理 Grafana 实例。让我们深入了解一些常用的 API:
-
仪表盘和文件夹:这些端点用于管理 Grafana 中的仪表盘和文件夹。它们的功能包括:
-
创建、读取、更新和删除仪表盘或文件夹的功能
-
创建、读取、更新和删除仪表盘上的标签
仪表盘和文件夹都有 ID 和 UID。ID 仅在特定的 Grafana 安装中是唯一的,而 UID 在不同的安装中是唯一的。
-
-
1=查看,2=编辑,4=管理员。可以为用户角色或teamId值设置权限。 -
文件夹/仪表盘搜索:此 API 允许用户搜索仪表盘和文件夹。该端点允许通过查询参数进行复杂的搜索。响应是一个包含对象 UID 的匹配对象列表。
-
团队:这些端点管理 Grafana 中的团队。可以用来执行以下操作:
-
创建、读取、更新和删除团队
-
获取、添加和移除团队成员
-
获取并更新团队偏好设置
-
-
警报:这些复杂的 API 管理警报的所有方面。此 API 管理与 Grafana Alertmanager 相关的所有内容。可以用来创建、读取、更新和删除警报、警报规则、警报组、静默、接收器、模板以及更多的警报对象。
这些 API 端点非常适合管理 Grafana。Grafana 提供了详细的 API 参考,链接为 grafana.com/docs/grafana/latest/developers/http_api/。
现在让我们看看这些 API 端点如何允许我们使用 Terraform 和 Ansible 的基础设施即代码(IaC)工具来管理仪表盘和警报。
使用 Terraform 或 Ansible 管理仪表盘和警报
由于仪表盘通常由负责某个服务或应用程序的团队管理,因此最佳实践是将部署仪表盘的工具与管理可观察性基础设施的工具分开。我们将在 第十四章 中讨论这个问题的实际操作。
在管理仪表盘时,Terraform 和 Ansible 都利用 Grafana 仪表盘是 JSON 对象的事实,提供了一种将包含仪表盘配置的 JSON 文件上传到 Grafana 实例的机制。让我们看看它是如何工作的。
Terraform 代码如下:
resource "grafana_dashboard" "top_level " {
config_json = file("top-level.json")
overwrite = true
}
一组仪表盘 JSON 文件可以通过 Terraform 的 fileset 函数和 for_each 命令进行迭代。这使得团队能够通过将正确的仪表盘保存到相关文件夹中,自动化地管理所有仪表盘。
Ansible 集合的工作方式非常相似:
- name: Create Top Level Dashboard
grafana.grafana.dashboard:
dashboard: "{{ lookup('ansible.builtin.file', ' top-level.json') }}"
grafana_url: "{{ grafana_url }}"
grafana_api_key: "{{ grafana_api_key }}"
state: present
与 Terraform 代码类似,这也可以使用内置的 with_fileglob 函数进行迭代,使得团队能够以自动化的方式管理所有的仪表盘。
不幸的是,由于 Grafana 在警报管理方面的最新变化,Ansible 集合尚未更新以支持警报管理。使用 Terraform,您可以以与仪表盘非常相似的方式管理 Grafana 警报。请考虑以下示例代码块:
resource "grafana_rule_group" "ateam_alert_rule" {
name = "A Team Alert Rules"
folder_uid = grafana_folder.rule_folder.uid
interval_seconds = 240
org_id = 1
rule {
name = "Alert Rule 1"
}
rule {
name = "Alert Rule 2"
}
我们没有包含这里展示的两个规则的完整细节,因为所需的配置块过大。Terraform 文档中有一个非常清晰的完整警报示例,链接为 registry.terraform.io/providers/grafana/grafana/latest/docs/resources/rule_group。
类似于 grafana_dashboard 资源,grafana_rule_group 可以通过使用 dynamic 块来遍历, 从其他源(例如 JSON 文件)填充每个规则。这样,管理这些规则变得更加用户友好。
总结
在本章中,你了解了自动化管理观察平台的好处,并看到投资于优秀的自动化可以让主题专家将重复性和低价值的工作交给组织中的其他人。我们讨论了观察平台的不同方面,包括数据生产、收集、存储和可视化。你还学习了通常由谁负责平台的每个方面。
理论部分大致讲解完后,我们继续讨论如何管理数据收集层,深入分析了用于收集本书中所有数据的 OpenTelemetry Collector Helm 配置。我们对比了 Helm 与 Ansible 在虚拟或物理环境部署中的工作方式,并帮助你掌握了理解每个工具管理文件结构的宝贵技能。我们通过介绍 Helm 图表和用于 Grafana Agent 的 Ansible 集合,完善了数据收集系统的自动化。虽然我们没有像 OpenTelemetry 配置那样深入讲解,但管理 Grafana Agent 所需的技能是相同的。
我们接下来的主题是 Grafana API,在这里你了解到有两个 API,一个用于管理 SaaS Grafana Cloud 解决方案,另一个用于管理 Grafana 实例(包括云端和本地)。然后,你学习了如何通过特定示例使用 Terraform 提供程序来管理云堆栈和 Grafana 实例。接着,我们也看了 Grafana Ansible 集合,了解了它如何用来管理云堆栈和 Grafana 实例,以及数据收集层。
在本书的下一章中,我们将讨论如何架构一个完整的观察平台,能够根据组织的需求进行扩展。
第十一章:架构化一个可观察性平台
本章涉及几个与架构化组织中团队可使用的优秀可观察性平台相关的主题。我们将讨论如何将数据结构化为领域,以帮助即使在最大型的组织中也能快速找到相关数据,以及这如何与其他业务方面(如财务报告和商业智能(BI))相关。接下来,我们将讨论架构化可观察性平台的四个主要系统组件:数据生产、数据收集、数据存储以及数据使用,如可视化和警报。我们还将讨论如何将架构与第十章中讨论的 IaC 工具相连接。之后,我们将讨论如何使用各种易得的工具通过本地测试验证设计。这些工具还可以在 CI/CD 管道中使用,以在实施更改后验证平台。我们将讨论在 Grafana 中实现的基于角色的访问控制(RBAC),以及如何设置它们以提供最小权限访问。最后,我们将简要讨论如何架构与其他系统的连接,这些系统利用相同的遥测数据,如安全信息和事件管理(SIEM)或 BI 系统。本章面向有平台和系统架构经验的高级技术读者。
在本章中,我们将讨论以下几个主要主题:
-
架构化你的可观察性平台
-
证明理论设计(概念验证)
-
设置正确的访问级别
-
向其他消费者发送遥测数据
架构化你的可观察性平台
理解并阐明组织所面临的问题是构建一个良好架构的可观察性平台中最关键且被低估的方面。虽然组织通常试图通过可观察性解决一些常见问题,但每个组织都是不同的,与像玛莎(如第一章中介绍的高级领导)这样的人合作,理解业务需求是一个常常被忽视的步骤,忽视这一点可能会导致未来出现复杂问题。
以下是一些组织常见的问题,可以通过可观察性平台来解决:
-
影响客户的事件:这类事件可能包括停机或数据泄露等。这些事件对组织构成合规性、操作性和声誉风险。客户可以是组织内部或外部的人员。
-
理解组织的关键绩效指标(KPI):组织通常希望清晰了解其 KPI 的当前状态。这些 KPI 阐明了组织的表现是否良好,或者是否存在需要解决的问题。
-
理解客户如何使用产品:理解客户如何与组织的产品互动可以识别痛点,并帮助引导更好的用户体验。提供优秀的产品能为组织带来竞争优势。
-
理解为客户提供服务的财务成本:这通常被称为销售成本(COGS)和运营 费用(OPEX)。
在本节中,我们将考虑如何构建可观察性平台中使用的数据结构,以支持组织的目标。我们将讨论设计系统架构的过程,以及在支持组织运营需求时需要考虑的因素。最后,我们将思考如何设计管理和自动化流程,使得按照最佳实践操作成为团队最容易采用的路径。
定义数据架构
数据架构定义了一个组织的数据资产,并映射数据在组织系统中的流动方式。大多数组织已经有了数据架构,因此值得与负责的团队进行讨论。在本节中,我们将讨论可观察性平台中的字段名称和数据类型如何与组织中的通用字段匹配或能够转换。
可观察性系统本质上是数据系统。它们收集、处理、传输、存储并使用数据。当可观察性系统中的数据与其他数据系统兼容时,对整个组织来说,它才最有价值,这样组织可以合并数据集。关键在于,在开始这项工作时,要与组织内部的人沟通,找出谁负责整个组织的数据架构。如果没有这样的人,可以向高层领导提出,将其视为解决问题的障碍。例如,当我还是一名初级工程师时,我记得参加过很多次会议,讨论tenantID和customerID是否是不同的字段,因为有两个系统使用了不同的名称。最终决定它们是不同的概念,以便业务能够捕捉到作为公司客户的母公司和子公司这一想法。然而,随后两个系统都需要数个月的工作来实现这一更广泛的概念。日志平台也需要大量的数据模型重建来捕捉这一新概念。如果有一个人负责数据模型并提前定义需求,这项工作本可以完全避免。
在实施可观测性平台时,通常会使用来自组织其他领域的数据模型。架构师应该完成一个步骤,将外部需求转化为需求文档,详细说明应在哪里记录字段。例如,财务数据模型可能要求记录成本中心。实现这一点有多种方法,例如:
-
要求每个日志行、每个度量和每个跟踪都包含这些信息
-
要求每个服务都必须加上
organization.costcenter标签 -
维护服务名称 ↔ 成本中心的查找表
要求指南应明确说明如何为将要满足这些要求的团队实现这一点。我们推荐使用如 MoSCoW 的文档结构,其中 MoSCoW 代表 必须有(Must have)、应该有(Should have)、可以有(Could have)、不会有(Won’t have)。
不同的遥测类型最适合不同的数据类型。可观测性系统还具备从其他系统收集数据的功能,例如 Kubernetes 对象标签和云标签。这些应构成数据架构的一部分。以下是一些遥测类型及其最适用的场景:
-
Loki 中的日志字段:日志字段最适合用于字符串数据,例如以下内容:
-
字符串格式的应用程序状态字段,例如 error 或 warn 状态,例如,如果一个应用程序查询数据并且无法连接到另一个服务
-
组织或业务数据字段,如服务名称、客户 ID、用户 ID 等
-
低到中等基数的索引字段
-
高基数的未索引字段
-
在跟踪中将应用程序状态链接到系统状态
-
-
Prometheus 或 Mimir 中的度量字段:度量字段最适合用于数值数据,例如以下内容:
-
数字格式的应用程序状态字段,例如自启动以来处理的记录数
-
组织或业务数据字段,包括包含服务名称、主机名等的标签
-
低到中等基数的字段,例如 HTTP 方法(GET、POST、PUT 等)
-
-
Tempo 中的跟踪字段:跟踪字段是一种复杂的数据类型,可以处理以下数据:
-
系统状态字段
-
高基数字段
-
作为属性添加的组织或业务数据字段,例如客户 ID 和用户 ID
-
跨系统字段
-
使用跟踪度量将应用程序状态链接到系统状态
-
-
Kubernetes 标签:这些是 Kubernetes 键值对数据对象。它们用于记录以下信息:
-
核心组织字段,如所有权和成本分配
-
将应用程序与基础设施连接
-
这些标签可以在收集日志、度量和跟踪数据时添加
-
-
云供应商标签:这些是应用于云供应商系统基础设施的标签。它们可以用来记录以下信息:
-
核心组织字段,如所有权和成本分配
-
在收集日志、指标和跟踪数据时,这些标签可以被添加到数据中。
-
这些数据在许多组织和行业中是标准化的,生成这些数据的库也经过了充分的测试。然而,有一个数据生成领域,这些工具并未进行测试,那就是组织特定的字段。这些字段总是与组织相关的,但一些常见的例子包括用户 ID 或客户 ID。当这些字段被组织使用时,它们可能非常重要,甚至会被高层领导定期审查。测试这些字段非常重要,因为错误的数据可能导致错误的决策。任何数据架构文档都应强调这一需求。实现这一目标需要大量的技术细节,我们在本书中不会深入探讨,但我们推荐 Martin Fowler 的这篇文章,其中清楚地说明了如何以可测试的方式生成组织数据:martinfowler.com/articles/domain-oriented-observability.html。
我们现在已经看到如何在组织内部工作,确保数据架构与基础设施层、应用层、可观察性层和业务层协同工作。现在让我们考虑如何为组织的可观察性平台构建一个优秀的系统架构。
建立系统架构
在本节中,我们将考虑构建一个出色的可观察性系统的各个方面。我们将探讨如何帮助软件工程师生成数据。接下来,我们将考虑如何收集这些数据,同时为工程师提供一个稳定的 API。最后,我们将讨论数据的存储和可视化。以下是与这些主题相关的一些需要考虑的问题:
-
数据将如何生成?
-
使用了哪些遥测类型(日志、指标、跟踪或其他)?
-
开发者,例如Diego,是否会获得库的标准?
-
是否应该将系统数据与业务数据分开?
-
-
数据将如何收集?
-
需要从哪些系统收集数据?
-
如果更改了工具,是否需要更新每个应用程序?
-
将收集多少数据?
-
-
数据将如何存储?
-
是否会提供任何本地存储?如果提供,如何管理其规模和成本?
-
存储是按集群或环境管理,还是作为一个集中式系统管理?
-
是否会使用第三方解决方案,如 Grafana Cloud?如果使用,如何分配成本?
-
-
可视化将如何管理?
-
系统是否完全开放,允许任何人提交任何仪表板的更改?
-
每个团队是否负责他们自己的仪表板?
-
是否提供 IaC 工具来帮助团队管理他们的仪表板?
-
-
这些问题的一个额外考虑因素是,所采用的系统如何处理故障
让我们更详细地讨论这些考虑因素,从架构化应用程序生成数据开始。
数据生成
数据生产说明了应用程序和服务如何生成数据。负责可观测性平台的团队应协助生成数据的团队,确保他们按照正确的字段、实践和标准进行数据生成。常见的讨论主题包括以下内容:
-
必须生成哪些遥测类型,哪些是应该生成的,哪些可以生成?
-
是否从可观测性系统中收集了组织或业务数据?如果收集了,字段是什么?是否使用了数据领域(例如,
acme.cost_center或acme.department)? -
开发人员是否需要使用预批准列表中的库?
-
应用程序用来呈现数据的标准是什么?
OpenTelemetry 虽然相对年轻,但正在成为可观测性的标准,并且在大多数供应商和系统中得到广泛采用。对应用程序的建议最佳实践是使用相关的 OpenTelemetry SDK 添加仪器化,具体请参见下图:

图 11.1 – 提议的应用程序数据生产标准
在这里,日志通过 stdout 和 stderr 输出。度量数据同时发布到 Prometheus 的抓取端点和通过 gRPC(端口 4317)或 HTTP(端口 4318)的 OpenTelemetry 接收器。追踪数据也会通过相同的端口推送到 OpenTelemetry 接收器。
生成数据只是构建良好架构系统的一部分。接下来,我们来看看如何设计一个系统来收集所有这些数据,使其对组织有用。
数据收集
我们在之前章节中讨论过的数据收集代理可以以多种格式收集数据。管理收集各种格式数据的基础设施是一项繁琐的挑战,容易出错且容易失败。系统架构需要详细说明哪些协议是首选的,哪些协议是可以接受的。对于成熟的组织,应该从当前正在使用的协议开始,并为任何计划移除的协议设定生命周期终止日期。强烈建议在存在默认端口时遵循默认端口,并在适用的环境中使用。
另一个考虑因素是数据是否将存储在本地、远程或两者兼有。本地存储增加了管理开销和成本,但在某些环境中可能是必需的。使用远程存储可以减少管理成本,但可能无法使用应用程序中的度量数据来做出环境选择。例如,Prometheus HorizontalPodAutoscaler(HPA)就是一个这样的例子。我们将在稍后的管理与自动化部分中详细讨论这个问题。作者过去在这类考虑中曾使用过短生命周期的易失性本地存储,同时使用远程的第三方提供的基础设施进行长期存储,这种配置效果良好。
OpenTelemetry 提供了几种配置。以下参考架构旨在为需要构建系统的读者提供一个起点。
例如,架构数据收集的最简单方式是每个应用程序将数据直接发送到后端,像这样:

图 11.2 – 无代理配置
对于演示或小型安装,这种架构是完全合适的。然而,每个应用程序都需要知道每个后端服务,这意味着这种安装类型的扩展性较差。
向应用程序添加本地代理增加了一些复杂性,但为管理应用程序的团队消除了大量的开销。这样的安装看起来像这样:

图 11.3 – 仅本地代理
运行本地代理是一种非常常见的模式,这种模式适用于许多环境。随着代理实例数量的增长,代理配置应使用某种形式的代码配置管理工具进行部署,如 Ansible、Salt 或 Kubernetes 环境中的 Helm。
添加网关服务是另一种常见架构。这种类型的安装看起来像这样:

图 11.4 – 仅网关代理
网关架构在几种情况下非常合适:
-
当本地实例的数量很高时,通过大量的打开连接可能会给后端系统带来压力。网关架构通过将负载分散到多个代理实例来解决这个问题。
-
网关架构非常适合那些目标是从 SNMP 或类似系统收集数据的安装。
最佳实践是将某种形式的负载均衡器放置在网关架构前面,并且在可能的情况下实现自动扩展。
Kubernetes 为数据收集架构引入了自己的挑战;下图尝试捕捉跨集群和节点收集数据所需的最常见工具:

图 11.5 – 更复杂的 Kubernetes 架构
思考这种配置的一种简单方式是将其分为三部分:
-
每个节点上都有一个本地代理配置。该代理配置为接收通过 gRPC 或 HTTP 传输的 OTLP 度量数据。该本地代理还配置为查询 kubelet 以获取与 Kubernetes 节点相关的统计信息。它还配置了一个主机接收器来收集度量数据;这在物理安装中是必需的。
-
网关代理也已配置。它从每个节点和集群代理收集数据。在这里使用网关代理也允许在网关中进行处理。
-
最终组件是集群代理。这是一个独立的代理实例,配置为从 Kubernetes API 服务收集数据。如果将此任务委派给所有节点或网关代理,则每个实例都会收集数据,从而在后端重复数据。通过使用独立实例,我们只获得一个数据流,并且该实例可以像节点代理一样利用网关。
还有许多其他配置可以使用,我们没有讨论使用多个不同代理的话题。然而,这应该为我们提供了一个基础,以便进行进一步工作。
我们现在已经了解了数据的生成和收集。这些系统对于所有组织来说都是相似的。接下来,让我们来看一下如何架构数据存储系统。
数据存储和数据可视化
关于可观察性平台的数据存储或可视化层,有一个关键问题需要问:谁负责?使用 Grafana 工具,可以轻松实现部署本地存储解决方案。这样,维护该平台的责任就由内部团队承担。另一种选择是使用与你的组织有合同关系的第三方。当出现问题时,这种关系非常有帮助。
我们在第四章、第五章和第六章中已经考虑了 Loki、Mimir 和 Tempo 的架构,因此我们不会展示每个工具的具体架构。接下来,让我们考虑一下,如果你有理由管理自己的存储,如何部署这些工具。
Grafana Mimir、Loki 和 Tempo 提供了多种部署模式:
-
单体模式:在单体模式下,所有微服务作为一个单一实例部署,并连接到对象存储。单体模式可以通过部署更多实例进行水平扩展。这种扩展方法可以提供高可用的平台,且复杂度较低,但缺点是不允许独立扩展读写路径。这个部署模式也不推荐用于生产环境。
-
微服务模式:此模式独立部署和扩展系统的每个组件。这增加了复杂性,但也使系统能够应对实际的负载。此模式是 Mimir 和 Tempo 生产环境使用的推荐部署模式。
-
简单可扩展模式(仅在 Loki 中可用):该模式在单体模式和微服务模式之间取得了平衡,允许独立部署和扩展写目标、读目标和后端目标。这些目标包含了执行其角色所需的所有服务。此模式是 Loki 生产环境使用的推荐部署模式。
对于这三种存储平台,部署是通过使用 Helm chart 进行 Kubernetes 部署的。此外,还提供了适用于 Linux 操作系统的部署包。通过提供的 Puppet 或 Tanka 包,可以实现自动化部署。
当您希望管理自己的数据可视化层时,需要安装 Grafana 应用程序。该应用程序可作为适用于 Linux、macOS 或 Windows 操作系统的包提供。Grafana 还提供 Docker 镜像,并提供详细的指导,帮助通过 Helm 部署到 Kubernetes。
处理系统故障
数据收集架构的一个重要考虑因素是如何处理故障。对于代理失败,唯一的实际选项是重启代理。然而,当收集管道失败时,可以通过在内存或磁盘中缓冲来处理。系统中的每个收集器都可以通过配置内存的批处理处理器和磁盘存储扩展来进行缓冲。设计缓冲解决方案时需要考虑的主要事项是系统需要容忍故障的时间。这个时间以及数据的吞吐量决定了实例必须具有多少内存或磁盘空间。将这个计算作为服务级指标(SLI)报告给数据收集层是一种良好的做法,因为它使系统的韧性公开可见。
我们现在已经了解了如何构建可观察性系统将要收集的数据架构,并且已经研究了如何构建收集该数据的系统。接下来,我们将考虑如何设计系统来考虑管理工具和自动化工具。
管理与自动化
我们在第十章中讨论了使用 IaC;在设计系统架构时,IaC 的使用应将四个系统(生产、采集、存储和可视化)作为独立的关注点来管理:
-
数据 生产系统:
-
这应该由各应用独立管理
-
应提供指导
-
-
数据 收集系统:
-
这通常由基础设施、平台、可观察性或类似团队进行管理
-
这应该像其他组件一样,公开发布 SLI 和 SLO
-
-
数据 存储系统:
-
这通常由基础设施、平台、可观察性或类似团队进行管理
-
通常使用第三方工具(如 Grafana Cloud)
-
Grafana Cloud 堆栈是一个很好的工具,可在必要时分离存储,例如,针对 CI/CD 平台或性能测试
-
-
数据 可视化系统:
-
该系统通常由基础设施、平台、可观察性或类似团队进行管理
-
与应用程序相关的仪表盘和其他工件应该由各应用团队独立管理
-
可以向团队提供 IaC 来管理部署
-
自动化架构设计不仅仅停留在可观察性平台上。部署到 Kubernetes 的应用程序应该能够根据需要自动扩展。当在数据生产部分建议理想的应用模式时,细心的读者可能已经注意到,我们建议通过 Prometheus 端点以及 OTLP 导出发布指标。这个建议是为了实现自动扩展。虽然本书关注的是 Grafana 中的可观察性,但一个真正可观察的系统可以自我修正,就像第一章中展示的蒸汽机调节器一样。Kubernetes HPA 允许根据 CPU 和内存使用情况对 Pods 进行扩展。这对于某些情况是可以的,但应用团队通常希望根据请求速率或会话数等指标进行扩展。Prometheus 社区为 Kubernetes Metrics API 提供了适配器,允许通过查询 Prometheus 端点来启用这些类型的扩展操作。一个重要的问题是,组织的架构应该由中央团队管理这种类型的监控,还是由每个应用团队管理,也许为团队提供一个默认配置供其使用。
我们已经了解了如何创建架构设计。有很多工具可以用来实践测试这些设计,证明它们可行。让我们来看一下如何验证架构。
开发概念验证
证明一个理论设计的最佳地方是一个实际有客户在交互的环境,也就是生产环境。这是因为其他任何环境都只是模拟环境,可能会忽略客户交互的一些细节。这个建议是尽早创建通向生产的路径,并定期使用它。提出这个建议之后,仍然非常重要的是为测试设计提供空间。
我们将讨论计算容器化和虚拟化工具,以及模拟数据生产工具,这些工具可以用来快速验证设计。
容器化和虚拟化
在本地使用容器化和虚拟化,并将其作为部署流水线的一部分,可以大大加速对集合或存储架构是否可行的反馈。让我们来看一些在这个领域有帮助的工具:
-
容器化:k3d、KinD、MicroK8s 和 minikube 等工具可以用于容器化,原因如下:
-
这四种工具都提供在本地运行 Kubernetes 集群的能力
-
KinD、k3d 和 minikube 可以使用 Docker 或 Podman 驱动程序运行
-
minikube 还提供了一个虚拟机驱动程序,对于某些本地安装非常有用
-
对于数据收集架构和流水线,作者使用 KinD 得到了非常好的结果
-
-
虚拟化:Vagrant 可以与多个虚拟化工具一起使用,包括 Hyper-V、VMware、VirtualBox、Xen、QEMU 和 libvirt。原因如下:
-
Vagrant 提供了定义虚拟机和虚拟网络的功能,并使用提供程序将这些定义部署到不同的虚拟化工具上
-
这是为实验和管道使用提供参考虚拟基础设施的一个宝贵特性
-
这些工具提供了构建参考基础设施的能力,可以在其上部署数据收集器。它们还提供了使用实际本地部署的设置来文档化架构需求和图表的功能。
部署基础设施和数据收集器是验证设计过程的一部分。拥有生成测试数据的工具同样至关重要,能够确保设计的正确性。现在让我们来看看这些工具。
数据生产工具
测试数据生成有几种方式——使用样例应用程序(如 OpenTelemetry 演示应用程序)或回放预录制的数据集:
-
演示应用程序:这些应用程序可用于生成实际的可观测性数据,以测试可观测性系统。以下是几个例子:
-
OpenTelemetry 演示应用程序:这是一个完整的零售应用程序,我们在本书中多次使用它来提供演示数据。
-
一个可观测性工作坊应用程序:这些应用程序由 AWS 提供,演示如何将数据推送到 AWS 可观测性工具中。
-
mythical-creatures 应用程序:这是 Heds Simons 为了与 Grafana 面试时编写的应用程序(他获得了这份工作)。该应用程序输出指标、日志和追踪。它比 OTEL 演示应用程序更简单,这也是一个优势。
-
-
预录制的数据集:这些应用程序可以用来生成预定义的数据集,用于测试可观测性系统。回放预录数据集的过程与负载测试和数据包捕获工具有很大的重叠。像 k6、Locust、Postman、Insomnia 和 GHZ 等工具可以用来向数据收集工具的收集端点发送预定义的数据块并验证输出。由于可观测性工具使用特定协议,因此需要查找与组织数据生产相匹配的特性。以下是一些例子:
-
发送 gRPC 数据的能力,因为这是 OpenTelemetry 中常见的格式
-
发送其他协议(如 SNMP)的能力,如果这些协议被使用的话
像 Fiddler 和 Wireshark 这样的工具,以及其他网络分析器或 HTTP(S) 调试器,可以用来记录网络数据,建立参考数据的库。
-
我们将在 第十四章 中详细讨论这些工具如何集成到 CI/CD 管道中。
我们现在已经了解了如何架构可观察平台的不同组件以及如何验证这些设计。另一个重要的架构考虑因素是如何正确设置访问级别。现在让我们来看一下这个问题。
设置正确的访问级别
我们已经讨论了可观察系统中的数据,以及如何架构实际的系统来生成、收集、存储和可视化数据。我们尚未讨论的一个重要架构元素是 RBAC(基于角色的访问控制)。
RBAC 可以应用的地方有两个:
-
Grafana Cloud:管理已部署的 Grafana 堆栈和账单。
-
Grafana 实例:访问数据和可视化内容。这些实例可以部署到 Grafana Cloud 或本地。
让我们先来看看目前在 Grafana Cloud 中可用的权限:
| 权限/角色 | 管理员 | 编辑者 | 查看者 |
|---|---|---|---|
| 查看 API 密钥 | ✓ | × | × |
| 管理 API 密钥 | ✓ | × | × |
| 查看组织账单信息 | ✓ | ✓ | ✓ |
| 管理组织账单信息 | ✓ | × | × |
| 管理 Grafana Cloud 订阅 | ✓ | × | × |
| 查看 Grafana 实例插件 | ✓ | ✓ | ✓ |
| 管理 Grafana 实例插件 | ✓ | × | × |
| 查看堆栈 | ✓ | ✓ | ✓ |
| 管理堆栈 | ✓ | ✓ | × |
| 管理组织成员 | ✓ | × | × |
| 查看发票 | ✓ | ✓ | ✓ |
| 支付发票 | ✓ | × | × |
| 查看企业许可证 | ✓ | ✓ | ✓ |
| 查看 OAuth 客户端 | ✓ | ✓ | ✓ |
| 管理 OAuth 客户端 | ✓ | × | × |
| 查看支持工单 | ✓ | ✓ | ✓ |
| 开放支持工单 | ✓ | ✓ | × |
表 11.1 – Grafana Cloud RBAC
这些 Grafana Cloud 角色专注于管理 Grafana Cloud 实例。对于大多数用户来说,使用和编辑一个或多个 Grafana 实例中的项目更适用于他们的日常工作。Grafana 提供了丰富的权限设置,具体分为以下几类:
-
基础角色:基础角色拥有非常广泛的权限。这对于小型组织以及便捷地访问新安装非常有用。将基本角色分配给用户,并且尽量采用最小权限原则是一个良好的做法。基础角色是一组默认的固定角色定义,我们将在下一个点中讨论。基础角色包括以下内容:
-
管理员:Grafana 组织的管理员。
-
编辑者:具有编辑组织中对象权限的用户。
-
查看者:具有查看对象权限的用户。
-
无:具有最小权限,通常用于服务账户。
-
Grafana 管理员:一个特殊的管理员账户,适用于所有本地实例中的 Grafana 组织。由于我们主要讨论的是 Grafana Cloud,下面来澄清一下什么是 Grafana 组织:
-
组织是一种方法,用于在单一实例中分隔 Grafana 资源。
-
在 Grafana Cloud 中,组织不可用。堆栈是更好的方法来分隔组织的部分,因为每个堆栈将使用专用的 Grafana 实例。
-
-
-
固定角色定义:固定角色可以用于扩展通过基本角色分配的权限。固定角色包含特定的权限分配,可以添加到主体上。
-
自定义角色:自定义角色允许创建具有特定权限、操作和作用域的角色。自定义角色只能通过 API 创建,但可以使用 Terraform 管理这些角色,作为基础设施即代码(IaC)的一部分。
权限还可以在数据源、团队、仪表板和文件夹级别分配。这可以实现一些结构,例如将所有文件夹中分配给特定团队的仪表板的管理权限授予该团队,但不授予其他团队文件夹的管理权限。所有的权限结构也可以使用 IaC 管理,我们在 第十章 中讨论了这一点。Grafana 提供了一份有关规划 RBAC 部署策略的有用指南,详情请见:grafana.com/docs/grafana/latest/administration/roles-and-permissions/access-control/plan-rbac-rollout-strategy/。
让我们考虑如何为我们的一些人物配置角色——Diego 开发者,Steven 服务,和 Pelé 产品:
-
作为负责某个服务的团队成员,Diego 需要能够读取仪表板,以了解其他服务的运行情况。他还需要对仪表板和警报具有写访问权限,但仅限于包含他负责的应用程序的文件夹。
-
Steven 需要能够查看仪表板,但不能编辑它们。然而,他确实需要能够查看和管理值班安排,并静音警报。
-
Pelé 有一些独特的需求。对于大多数日常流程,他需要能够查看仪表板、事件历史,并查询关于他负责的产品应用程序的数据。然而,他还需要一个服务账户,以便运行特定的查询,获取业务指标并将数据加载到与 Masha 经理 一起使用的 BI 平台中,用于分析团队是否需要任何帮助来交付出色的产品。他与 Ophelia(Grafana 系统的管理员)一起工作,设置了这个具有有限权限的服务账户。
对于大多数用户,一旦角色创建完成,接下来就是将角色分配给单个用户的过程。对于服务账户应特别考虑。一些服务账户,例如由管理 Grafana 工具提供的团队使用的账户,将需要较大的访问权限,并应进行彻底审计。其他账户,例如由单个应用程序团队管理仪表板时使用的账户,应具有有限的权限。对于这种第二种类型的账户,建议将管理服务账户的有限权限授予团队中的高级成员,因为这能让团队独立工作。
现在我们理解了 Grafana 中的 RBAC,让我们看看 Grafana 收集的数据如何在其他系统中使用。
将遥测数据发送给其他消费者
可观测性系统收集的数据通常在其他系统中使用。日志通常在 SIEM 系统中使用,聚合指标在 BI 系统中很有用。有两种不同的策略可以用来与其他消费者共享遥测数据:
-
在收集管道中共享数据:在收集管道中共享数据取决于正在使用的数据收集管道。我们已经讨论了 OpenTelemetry 收集器,它提供了过滤和将数据发送到多个后端系统的功能。同样,AWS、GCP 和 Azure 提供了将遥测数据写入多个后端系统的选项。需要考虑的是,这种类型的解决方案会通过存储相同数据的多个副本来增加成本。建议与其他消费者共同花时间了解其需求,以最小化这种成本。
-
直接从 Grafana 查询数据:通过定期运行直接针对 Grafana 的查询来查询数据。这些通常是自定义连接器,将读取数据并将其写入 BI 平台。Grafana 提供了记录规则功能,可以帮助进行数据收集。此功能允许预计算查询,并将其存储为单独的时间序列。例如,如果业务关心每天登录的唯一用户数,则记录规则可以查询此数据并将其存储为新的指标。当 BI 平台收集这些数据时,不需要等待潜在的缓慢查询完成,而是可以轻松获取数据。
现在,您应该对设计符合组织需求的全面可观测平台并向组织内其他系统提供有价值信息感到自信了。
总结
在本章中,我们探讨了设计数据字段的过程,这些字段将被收集起来。您可以利用这些知识,在 Grafana 平台上结构化数据,使其在整个组织中易于使用。我们讨论了通过应用程序进行数据生产的过程,并提供了关于最佳应用程序结构的标准指导。这将满足组织中开发人员的大部分需求。我们分享了数据收集架构的几个复杂级别。您可以将它们用作构建自己系统的起点。我们讨论了用于验证架构设计的各种工具:既有用于运行本地基础设施的工具,也有用于模拟正在收集的数据的工具。这将有助于生成可靠的可观察性平台基础设施交付管道。最后,我们简要讨论了如何与其他消费者共享数据,无论是在数据收集管道中还是通过直接查询 Grafana。您可以利用这些知识将可观察性数据链接回组织的其余部分。
在下一章中,我们将探讨使用真实用户监控(RUM)直接从浏览器收集数据。这提供了在用户活跃系统中运行代码的可见性。
第四部分:Grafana 的高级应用和最佳实践
有许多与可观察性相关的主题,包括前端可观察性、应用程序性能、负载测试、DevOps 流水线和监视安全应用程序。本部分将讨论这些主题,并额外关注可能的未来趋势。最后,我们将总结一些最佳实践和故障排除方法。
本部分包括以下章节:
-
第十二章**,通过 Grafana 进行真实用户监控
-
第十三章**,使用 Grafana Pyroscope 和 k6 进行应用程序性能
-
第十四章**,支持 DevOps 流程的可观察性
-
第十五章**,故障排除、实施最佳实践及其他 Grafana 功能
第十二章:使用 Grafana 进行真实用户监控
在本章中,我们将探讨使用 Grafana Cloud 前端可观察性 和 Faro Web SDK 进行 真实用户监控(RUM)。我们将了解什么是 RUM,如何利用它解决实际用户问题,以及一些需要关注的重要指标。接着,我们将介绍如何在 Grafana Cloud 实例中设置前端可观察性,以及其中包含的预构建仪表盘。我们还将探讨如何将前端可观察性数据与后端遥测数据关联,形成更完整的视图。最后,我们将讨论收集前端数据的最佳实践。
在本章中,我们将涵盖以下主要内容:
-
引入 RUM
-
设置 Grafana 前端可观察性
-
探索 Web Vitals
-
从前端到后端数据的转换
-
增强和自定义配置
引入 RUM
RUM 是描述收集和处理浏览器遥测数据的术语,用于描述你 web 应用前端的健康状况。它让我们从用户浏览器到后端系统,实时地鸟瞰用户交易的全过程。这种遥测数据的好处在于,它为我们提供了用户实际体验的洞察,尤其是应用的性能表现。
Grafana 通过以下组合实现 RUM:
-
Grafana Faro Web SDK,当嵌入到你的 web 应用中时,默认收集以下遥测数据:
-
Web Vitals 性能指标
-
未处理的异常
-
浏览器环境信息
-
页面 URL 变化
-
会话标识(用于数据关联)
-
活动轨迹
除了默认设置外,SDK 还可以配置为将自定义元数据、度量和指标发送到 Grafana,以增强前端可观察性。Faro Web SDK 集成了 opentelemetry-js,提供基于 Open Telemetry 的应用程序追踪。此 SDK 是开源的,仓库地址为
github.com/grafana/faro-web-sdk,并附有详细文档和示范代码。 -
-
一个云托管的浏览器遥测接收器(你也可以选择在自己的基础设施上部署 Grafana Agent)。云托管接收器会在你启用 Grafana Cloud 的应用可观察性时创建并配置(我们将在下一节带你完成设置步骤)。
-
每个你创建的前端可观察性应用,都有一个专用的 Grafana 应用界面,其中包含作为标签的仪表盘(我们将在本章稍后部分讨论这些仪表盘标签)。
下图展示了左侧框中安装了 Faro Web SDK 的 前端应用 和右侧框中用于摄取、存储和展示遥测数据的 Grafana Cloud 组件 之间的关系:

图 12.1 – 前端关系图
Grafana Faro Web SDK 收集遥测并将其转发到 Grafana Cloud 中的收集器端点,然后处理并发送到适当的后端 – Loki 用于日志和 Tempo 用于跟踪。通过 Loki 的 LogQL 度量查询生成指标,我们在第四章 中讨论过。生成的指标在 Grafana Cloud 前端可观测性应用程序仪表板中显示。
现在让我们看一下设置 Grafana 前端可观测性的步骤。
设置 Grafana 前端可观测性
要开始监视您的应用程序前端并配置 Grafana Cloud 前端可观测性,请按照以下步骤操作:
- 在您的 Grafana 实例中,从菜单中选择 可观测性 | 前端:

图 12.2 – Grafana 可观测菜单
- 前端应用程序 登录页面将显示。如果这是您第一次来到这里,您将看到一个 开始观察 按钮 – 请点击它。

图 12.3 – Grafana 云前端可观测屏幕
如果您已经设置了前端应用程序,它们将在此列出,并且会有一个 创建新 按钮,而不是 开始观察 按钮。单击任一按钮都会显示 创建新应用 弹出窗口。
- 在 图 12**.4 中显示的 创建新应用 弹出窗口需要一个应用程序名称,跨域资源共享 (CORS) 地址和额外的标签详细信息(这些是要添加到 Loki 日志中的标签,当它们进入 Grafana Cloud 时)。此外,您还将被要求确认与此功能的额外遥测相关的云成本:

图 12.4 – 创建新应用屏幕
- 完成表单后,将为您提供几种选项,以便使用 NPM、带有跟踪的 CDN 或 不带跟踪的 CDN 将 Faro Web SDK 集成到您的前端应用程序中。您需要决定哪种最适合您的应用程序开发要求:

图 12. 5 – Web SDK 配置
当您在应用程序中连接 Faro Web SDK 到 Grafana 时,我们在本节开头确认的默认遥测将开始发送。
您的可观测性前端应用程序的 概述 标签将类似于以下截图,并包含在 Grafana 前端可观测性中显示的关键指标的主要仪表板:

图 12.6 – 前端可观测性概述标签
在 概述 标签旁边是 错误 和 会话 标签,帮助您调查您的应用。让我们更详细地看看这些标签:
-
仪表板顶部行的 概览 标签显示了重要的 Web 重要指标,包括 核心 Web 重要指标。Web 重要指标是谷歌发起的一项计划,旨在为报告网页用户体验所需的关键指标提供统一的指导。
-
错误 标签详细列出了任何前端异常、异常发生的位置以及受影响的浏览器:

图 12.7 – 前端可观察性错误标签
- 会话 标签展示了可供分析的用户会话列表。我们将在 从前端到后端的转变 数据 部分详细探讨这一点。
设置 和 Web SDK 配置 标签帮助你配置连接(设置 允许你修改本节第 3 步中输入的值,Web SDK 配置 提供了第 4 步中看到的配置)。
在接下来的部分,我们将更详细地查看 Web 重要指标,以了解我们为前端应用程序捕获和报告的信息。
探索 Web 重要指标
为了说明提供给用户的体验质量,Web 重要指标报告了用户交互的多个方面。Web 重要指标是谷歌的一项计划,旨在为提供出色的网页用户体验所必需的质量信号提供统一的指导。你可以在 web.dev/articles/vitals 上阅读有关 Web 重要指标项目的详细信息,特别是有关核心 Web 重要指标的信息,详见 web.dev/vitals/#core-web-vitals。
在 概览 标签中使用的重要 Web 重要指标如下:
| 指标 | 描述 |
|---|---|
| 核心 Web 重要指标 | |
| 最大内容绘制 (LCP) | LCP 指标衡量的是相对于页面开始加载时,最大可见部分的显示时间。这可能是完全加载的文本或图像,显示在访客的屏幕上。目标 LCP 应 <= 2.5 秒。更多详情,请参考 web.dev/articles/lcp。 |
| 首次输入 延迟 (FID) | FID 指标衡量的是访客点击链接到浏览器开始处理该事件之间的时间。目标 FID 应 <= 100 毫秒。更多详情,请参考 web.dev/articles/fid。计划在 2024 年 3 月将 FID 替换为 与下一次绘制的交互 (INP) 作为核心 Web 重要指标。 |
| 累计布局 偏移 (CLS) | CLS 指标衡量的是任何可见元素位置发生变化的情况。当访客体验布局变化时,持续时间会被捕获,累计得分会被报告。目标 CLS 应 <= 0.1。更多详情,请参考 web.dev/articles/cls。 |
| 其他 Web 重要指标 | |
| 首次字节时间 (TTFB) | TTFB 指标衡量的是从请求网页资源到响应的第一个字节开始到达之间的时间。访问者通常无法察觉到这一点,但它是衡量响应性、内容传递到访客的一个良好指标。目标 TTFB 应小于等于 0.8 秒。更多详细信息,请参考web.dev/articles/ttfb。 |
| 首次内容绘制 (FCP) | FCP 指标衡量的是从页面开始加载到页面任何部分显示在屏幕上的时间——本质上,就是当你的访客实际看到他们请求的网站内容时的时间。目标 FCP 应小于等于 1.8 秒。更多详细信息,请参考web.dev/articles/fcp。 |
| 交互到下一页 绘制 (INP) | INP 指标衡量的是页面在访问者会话期间的响应速度。它通过观察每一次点击、触摸和键盘交互的延迟来实现这一点,并取最长的延迟(忽略异常值)。INP 的目标值应小于等于 200 毫秒。更多详细信息,请参考web.dev/articles/inp。 |
表 12.1 – 重要的 Web Vitals 指标
现在我们已经了解了一些需要考虑的重要前端指标,让我们来看看在调查问题时,如何将注意力转向后端遥测数据。
从前端数据转向后端数据
一旦你开始收集前端可观察性数据,你将能够将其与后端和基础设施的遥测数据进行关联。当你使用 Loki 来处理日志、Tempo 来处理跟踪、以及 Mimir 来处理指标时,Grafana 为你提供了简单的接口来实现这一目标。
在 Grafana Cloud 前端可观察性应用中,有现成的仪表板使得导航和调查变得简单。正如在设置 Grafana 前端可观察性部分中讨论的那样,应用菜单有三个主要部分,分别是概览、错误和会话。会话选项卡允许我们进入系统生成并发送到 Grafana 的其他遥测数据。你可以在下面的截图中看到多个请求指向不同的页面 URL,以及相关的会话 ID:

图 12.8 – 会话选项卡
点击会话 ID条目将带你进入详细视图,在那里你可以看到该特定访问者会话的 Web Vitals,相关的异常,以及如果你对系统的其他部分进行了监控,还可以看到跟踪链接:

图 12.9 – 会话详情屏幕
选择追踪将带您进入探索视图,查看完整的系统追踪,您可以轻松导航到来自后端的关联 Loki 日志,提供了浏览系统的能力。这展示了通过全链路可观测性仪表盘所能带来的额外价值:

图 12.10 – 系统追踪的探索视图
默认会话的定义如下:
-
会话开始:访问者进入网页,初始化 Faro,开始一个新的会话
-
会话结束:访问者离开页面,会话被销毁(默认情况下,不会发送会话结束事件)
然而,您可以根据自己的使用案例定义会话逻辑。Faro 的会话仪表化文档可以参考grafana.com/docs/grafana-cloud/monitor-applications/frontend-observability/faro-web-sdk/components/provided-instrumentations/#session-tracking中的可用配置。
现在让我们来看看考虑前端可观测性时的一些最佳实践。
增强功能和自定义配置
在所有可观测性中,您需要考虑您的使用案例。这在考虑前端可观测性时尤为重要,因为您将在访问者的浏览器中操作。有几个增强功能可以在默认实现的基础上改进前端可观测性。然而,这些增强功能需要额外的配置、更多的开发工作,并且可能对访问者的浏览器产生更大的影响。不过,它们可以显著提高前端可观测性仪表盘所提供的价值。
让我们探讨一下前端可观测性的增强功能:
-
前端追踪:提供了更好的关联性,能够将真实用户交互与后端事件联系起来。它需要额外的 OpenTelemetry SDK 配置,并且会增加一定的浏览器负载,因此需要仔细考虑其影响并进行测试。
-
自定义错误:为具有错误处理的系统提供了改进的可观测性。需要额外配置,手动将 Faro Web SDK 添加到错误处理管道中,以将错误推送到 Grafana。
-
自定义度量:提供了增强的遥测功能,包含应用特定的数据。需要额外配置,手动将 Faro Web SDK 添加到管道中,以将额外的度量数据推送到 Grafana。
-
自定义日志:提供了发送支持元数据的能力,帮助您了解访问者的体验。需要额外配置和开发工作来进行仪表化。
-
kind=event。我们在第四章中学习了有关 Loki 标签的所有内容。
如果你没有准备好前端应用程序进行仪表化,可以使用 Faro Web SDK 提供的演示项目进行实验。这将帮助你更详细地了解发生了什么以及它是如何工作的:github.com/grafana/faro-web-sdk/blob/main/demo/README.md。
现在让我们总结本章内容,并展望下一章。
总结
在本章中,我们探讨了用户监控以及通过全面的端到端可观察性仪表化所获得的额外价值。我们了解了 Grafana 如何通过 Grafana 前端可观察性和 Faro Web SDK 提供这一能力。接着,我们看到了 Web Vitals 指标,这对于解读访客体验非常重要。我们还研究了内置仪表板,它们帮助你在 Grafana 中导航到后端遥测数据,赋予你完全诊断问题的能力。最后,我们探讨了一些前端可观察性的最佳实践和自定义配置。
在下一章,我们将学习如何使用Pyroscope和k6从 Grafana 监测应用程序性能的不同方面。
第十三章:使用 Grafana Pyroscope 和 k6 进行应用性能分析
本章将探讨两个工具,Pyroscope 和 k6。Pyroscope 是一个 持续性能分析 工具,允许用户收集关于系统资源使用的非常详细的信息,比如 CPU 和内存。k6 是一个 负载测试 工具,可以通过端点与应用程序交互,或通过脚本方式在浏览器会话中使用。
在 Pyroscope 中,我们将学习如何搜索数据,这将帮助您更好地理解如何利用可用数据。接着,我们将展示如何通过安装客户端或向应用代码中添加原生语言 SDK 来加入插桩以收集这些数据。最后,我们将看到 Pyroscope 新版本的架构如何利用 Grafana 在高可扩展存储平台方面的知识,使用廉价的块存储将 Pyroscope 带入为开发者提供真正持续性能分析的路径。这项功能将帮助那些需要查看代码执行情况的人,改善运营成本或最终用户性能。
k6 将稍微偏离可观察性,进入与之紧密相关的负载或性能测试领域。我们将讨论负载测试的一般原则,并查看您可能需要的不同类别的负载测试。接着,您将学习 k6 使用的脚本语言,方便编写测试来验证应用程序是否按预期运行。我们将了解 k6 如何使用 虚拟用户(VUs)来扩展测试并为应用程序创造显著负载,您可以利用它证明您的应用程序按预期运行。最后,我们将看到如何安装 k6,以及它如何足够灵活,甚至可以作为 CI 流水线的一部分运行,确保您的应用程序持续接受负载测试。
本章我们将涵盖以下主要内容:
-
使用 Pyroscope 进行持续性能分析
-
使用 k6 进行负载测试
使用 Pyroscope 进行持续性能分析
首先,让我们解决一个问题,那就是连续剖析是什么。如同本书开头所提到的,当系统的内部状态可以从其外部输出中推测出来时,系统是可观察的。我们已经看到了三种输出遥测:日志、指标和追踪。剖析数据是另一种遥测形式。剖析数据是与工作负载资源使用相关的低级数据,如 CPU 或内存的使用情况。由于剖析工具分析的是非常底层的系统数据,它们捕获的信息包括特定应用函数的运行时间或内存中的对象数量。这对于领域专家检查应用程序行为非常有力,这种能力能够带来显著的性能和成本改进。剖析技术已经存在很长时间了,任何生成过堆栈跟踪的人都会知道这一点。Pyroscope 提供了连续捕获这种剖析数据的能力,默认间隔为 15 秒。能够在应用程序的生命周期内持续收集这些遥测数据,可以深入了解应用程序随时间的运行情况,这能够将代码库的内部工作与日志、指标和追踪中看到的特定用户行为联系起来。
在本节中,我们将简要介绍 Pyroscope。你将学习如何搜索 Pyroscope 收集的数据。我们将讨论如何配置客户端以收集剖析数据,并将研究 Pyroscope 服务器的架构。
Pyroscope 简介
Pyroscope,也被称为 Grafana Cloud Profiles,成立于 2020 年,并在 2023 年被 Grafana Labs 收购。Pyroscope 团队从 Grafana Labs 的一个实验性产品 Phlare 中加入,该产品现在成为了 Grafana Cloud 的标准产品之一。Pyroscope 的一些关键特性如下:
-
使用与 Loki、Mimir 和 Tempo 相同架构的优秀水平扩展性
-
剖析数据的廉价存储
-
可以将数据存储在本地或使用 Grafana Cloud
-
高频率采样,产生非常细粒度的数据
现在,让我们来探讨如何检查 Pyroscope 收集的数据。
搜索 Pyroscope 数据
可以通过在 Grafana UI 中选择 Pyroscope 数据源,使用Explore视图查看剖析遥测数据。虽然该视图与 Loki、Mimir 和 Tempo 类似,但查询语言受到遥测类型的限制;实际上,只能使用选择功能,通过标签选择来自应用程序或应用程序组的信号。你将在此视图中看到用于选择 Pyroscope 数据源数据的界面:

图 13.1 – Pyroscope 查询面板
第一个需要查看的视图是top命令,这个视图应该是熟悉的。该视图列出了每个函数及其所花费的时间。Self列显示该函数所花费的时间。Total列显示每个函数运行的总时间。这可以帮助用户查看运行时间较长的函数。较长的运行时间可能表明一个低效的函数,但也可能意味着这个函数对应用程序至关重要。需要领域知识才能理解在哪些地方可以进行改进。以下截图显示了Top Table视图:

图 13.2 – Pyroscope 顶部表格视图
第二个视图是火焰图视图。这个图表专门设计用来可视化分析数据。火焰图的发明是为了能够可视化应用程序的堆栈跟踪输出,从而简化调试工作。在我们查看 Pyroscope 中的视图之前,先来看一个示例应用程序的堆栈跟踪:

图 13.3 – 示例应用程序堆栈跟踪
我们可以看到有一个main()函数,它在应用程序启动时被调用。这个函数依次调用子函数foo()和bar(),而bar()也会调用baz()和qux()函数。火焰图通过将子函数分组在其父函数下,捕捉了这些堆栈调用的层次结构。这让我们能够通过查看y轴来了解调用堆栈的深度。函数的总数量显示在x轴上;重要的是,这不代表时间,而是每个在采样期间出现在调用堆栈中的函数。火焰图中每个函数的框宽度表示该函数在采样期间花费的总时间,进而可视化了每个函数的持续时间。我们来看看这个实际的例子:

图 13.4 – 来自堆栈跟踪的示例火焰图
在这个示例火焰图中,我们可以看到baz()函数占用了大量的操作时间。在某些应用程序中,这是完全预期的行为;而在其他应用程序中,这可能表明需要优化的函数。
很少有应用程序像这个示例一样简单。接下来,我们看看 OpenTelemetry 演示应用程序中的真实火焰图:

图 13.5 – 一个真实的火焰图
我们已经看到像 Pyroscope 这样的连续分析工具在编写高效代码和调试问题中非常有价值。接下来,我们来看看如何收集分析数据。
连续分析客户端配置
目前有三种独立的方式收集 Pyroscope 的数据,尽管我们预期随着 Pyroscope 技术的不断发展,这些方式将会演变。对于那些希望了解此项激动人心技术最新进展的朋友,我们建议参考 Grafana Labs 的博客(https://grafana.com/blog/)。接下来,让我们探讨如何设置每一种方法:
- 扩展伯克利数据包过滤器(eBPF)客户端:收集 Pyroscope 配置数据的第一种方法是利用 Linux 内核级工具 eBPF。这个工具允许配置客户端查看服务器或节点上运行的所有应用程序的跟踪信息。eBPF 客户端将这些数据与数据源的元数据(例如 Kubernetes Pod 或命名空间)结合,然后将这些配置信息发送到 Pyroscope 后端。下图显示了 eBPF 如何为 Pyroscope 客户端收集数据的简化视图:

图 13.6 – eBPF 客户端进程
使用 eBPF 时,内核收集配置数据以及其他几种类型的数据,并将其存储在 eBPF 映射中。Pyroscope 将数据链接到 eBPF 映射中,打包数据,然后将其发送到配置的后端进行存储。
-
本地语言仪器:收集配置数据的第二种方法是使用特定语言的 Pyroscope SDK 向应用程序添加仪器。目前,Go、Java、.NET、Python、Ruby、Rust 和 Node.js 都提供 SDK。除了 Go SDK 之外,所有这些库仅支持推送模式操作。Go 支持推送和拉取模式操作;拉取模式允许 Grafana 代理从应用程序发布的抓取端点收集配置数据。在推送模式下,目前需要在应用程序级别添加 Pyroscope 服务器地址、基本身份验证用户名和密码,尽管随着该工具的成熟,我们相信这将在操作环境中变得更易于管理。
-
仪器化 Lambda 函数:Pyroscope 还为 AWS Lambda 函数提供工具。这包括一个 Lambda 扩展,当函数被触发时,作为一个层加载。这样,配置工具可以异步收集所需的配置遥测数据,而不影响 Lambda 函数的操作。与本地语言仪器一样,必须提供环境变量,其中包括 Pyroscope 后端的远程地址和相关的身份验证令牌。
对于运行无服务器函数的团队,这为查看 Lambda 函数的“黑匣子”提供了能力,并允许团队回答以下问题:为什么我的 Lambda 费用这么高?,为什么我的延迟这么高?,以及为什么我的函数 这么频繁失败?
eBPF 客户端、SDK 和 Lambda 方法各有利弊:它们的使用取决于使用场景。以下是每种方法的一些优缺点:
| 工具化方法 | 优点 | 缺点 |
|---|---|---|
| eBPF | 可以轻松收集全系统的系统级配置文件。基础设施元数据易于添加(例如,Kubernetes Pod 或命名空间)。易于管理多语言或大型系统。可以与本地语言工具化结合使用。 | Linux 内核限制。标记用户级代码的能力有限。一些配置文件类型的收集性能差(例如,内存使用)。本地开发环境更为复杂。 |
| 本地语言 | 灵活标记代码。对代码特定部分进行详细分析。能够分析其他类型的数据(例如,内存使用)。在本地开发环境中使用简单。 | 管理多语言或大型系统比较困难。难以自动标记基础设施元数据(例如,Kubernetes Pod 或命名空间)。 |
| Lambda 函数 | 允许从无服务器函数收集追踪数据。与本地语言支持相连接以对函数进行工具化。 | 当前仅适用于 AWS Lambda。 |
表 13.1 – Pyroscope 工具化方法的优缺点
我们已经看过了不同的应用程序和客户端设置方式来收集配置数据。接下来,让我们考虑 Pyroscope 的存储和查询架构。
理解 Pyroscope 架构
Pyroscope 1.0 引入了对 Pyroscope 架构的重大变化。该变化利用了 Grafana 对 Cortex 架构的知识,使架构具备水平扩展能力。这是与之前版本的断裂性变化,因此我们将仅考虑从这个变化开始的架构。
类似于 Loki、Mimir 和 Tempo,Pyroscope 使用低成本、高可用的块存储,如 Amazon S3、Google Cloud Storage 或 Microsoft Azure Storage,以提供大规模扩展能力。以下是 Pyroscope 架构的示意图:

图 13.7 – Pyroscope 架构
当数据被写入时,它会被发送到 Ingester,该组件将数据持久化到 对象存储。在 读取 方面,查询被拆分并分片到 Querier 实例,后者从 Ingester 和/或长期存储中获取所需的数据。
市场上有几个替代 Pyroscope 的工具可能会引起你的兴趣。开源工具包括 OpenTelemetry eBPF、Parca 和 profefe,还有几个观察性供应商也提供类似的分析工具。这些工具可以在 github.com/open-telemetry/opentelemetry-ebpf、www.parca.dev/ 和 https://github.com/profefe/profefe 找到。我们现在已经看过了 Pyroscope 的功能。另一个对开发人员和测试人员有帮助的工具是 k6 负载测试。接下来让我们看一下这个工具。
使用 k6 进行负载测试
负载测试是将已知的人工负载施加到应用程序上,以观察其行为的实践。这个术语通常与性能测试交替使用,我们将遵循 k6 文档,使用平均负载来区分特定类型的测试。
可以应用几种不同类型的负载测试;它们在两个维度上有所不同——负载吞吐量和持续时间。它们在执行的测试内容上也可能不同。下表展示了一些常见的测试类型:
| 测试 | 描述 | 目的 | 运行时长 与流量 |
|---|---|---|---|
| 冒烟测试 | 这些测试旨在验证系统是否正常工作。它们也可以称为健全性测试或信心测试。冒烟测试这个名称源自测试设备时,通过开启设备并检查是否冒烟。 | 这些测试旨在快速验证系统是否符合预期,或者是否存在问题。 | 这些测试应该快速进行,通常是几分钟而非几小时。它们应为低流量。 |
| 平均 负载测试 | 这些测试展示了系统在大多数条件下的使用情况。 | 这些测试旨在模拟系统上最常见的负载水平。 | 这些测试应该相对快速地进行,但比冒烟测试慢。它们应模拟平均流量。 |
| 压力测试 | 这些测试通过高于平均水平的峰值流量来测试系统。 | 这些测试旨在模拟如果在较长时间内经历峰值流量时系统会发生什么。 | 这些测试应该在一天之内完成。它们应模拟大量流量。 |
| 峰值测试 | 这些测试应该展示系统在短时间内经历突如其来的、大量的流量激增时的表现,就像在拒绝服务(DoS)攻击中看到的那样。 | 这些测试旨在测试系统如何应对突如其来的、极大的流量激增,如 DoS 攻击。 | 这些测试应该快速进行。它们应模拟不现实的大量流量。 |
| 突破点测试 | 这些测试逐渐增加流量,直到系统崩溃。 | 这些测试旨在了解在负载增加时系统何时会失败。 | 这些测试可以运行较长时间。它们应模拟稳定增长的流量速率。 |
| 浸泡测试 | 这些测试评估系统在长时间运行下的性能。它们类似于在显著更长时间内进行的平均负载测试。 | 这些测试旨在展示系统在实际操作中长时间运行时的表现。它们适用于发现诸如内存泄漏等问题。 | 这些测试将运行较长时间,如 48 小时。它们应模拟平均流量。 |
表 13.2 – 负载测试类型
下图展示了不同的测试,供参考:

图 13.8 – 不同负载测试类型的视觉表示
在前面的图中,我们可以看到通过测试吞吐量和测试持续时间来绘制的不同类型的测试。尝试将你在图表中看到的内容与在表 13.2中学到的这些测试相对应。
你可以看到,负载测试和可观察性紧密相关。从实时系统收集的数据将展示出什么是平均负载和不现实的负载。通过冒烟测试注入的数据可以显示系统是否按预期工作,例如在新版本部署后。负载测试环境中收集的数据可以提供关于系统在负载下运行的关键见解。
将从负载测试中收集到的可观察性数据与其他数据分开是一个良好的实践。由于所尝试的测试的性质,可能会生成大量数据,这可能会是一个非常昂贵的收集过程。像 Grafana 这样的开源系统的一个巨大优势是能够将数据存储系统作为负载测试环境的一部分运行,并使用与生产环境中相同的可视化方式。
市场上有几种负载测试工具,既有开源的也有商业的。开源工具包括 JMeter、k6、Gatling、Locust、Artillery、Tsung、Vegeta、Hey 和 Siege。由于本书关注 Grafana 工具,我们这里只讨论 k6。让我们来看看 k6 的一些特点。
k6 简介
k6 是由 Grafana Labs 在收购 LoadImpact 后开发的负载测试工具。k6 提供了几个关键特性:
-
一个命令行接口(CLI),可以用于运行、暂停、恢复或扩展测试。
-
能够在本地、Kubernetes 集群或通过 CLI 在云端启动测试。k6 支持通过 Kubernetes 操作员进行分布式运行。
-
使用 JavaScript 的脚本支持。
-
将额外的模块加载到脚本中的能力,尽管这不包括对 Node.js 模块的支持。
-
一个浏览器模块,添加浏览器级别的 API,用于完整的前端测试。
-
支持使用检查和阈值进行目标导向的负载测试。
-
很好的支持工具,如下所示:
-
参考项目
-
将其他工具的脚本转换为 k6 的工具
-
将 k6 输出转换为其他常见格式的工具
-
一个图形界面用于测试构建
-
现在让我们看一下编写简单测试的过程。
重要提示
由于 k6 需要测试文件才能运行,我们在这些编写测试的说明后面加入了安装和使用说明。
使用检查编写测试
测试是使用 JavaScript 在 k6 中编写的。一个非常简单的测试示例,向 acme 网站提交一个 GET 请求,可能是这样的:
import http from 'k6/http';
export default function () {
http.get('http://www.acme.com');
}
这个脚本仅仅会向网页提交请求,但不会验证请求是否成功。check 功能用于确认请求是否成功,如下所示:
import { check } from 'k6';
import http from 'k6/http';
export default function () {
const res = http.get('http://www.acme.com');
check(res, {
'is status 200': (r) => r.status === 200,
},
{ company: 'Acme' }
);
}
check()函数接受一个值,一个包含要针对该值运行的检查的对象,以及一个包含任何标签的对象。如果所有检查通过,则该函数返回true;否则,它返回false。check功能使得在脚本中检查简单条件变得非常容易。通常需要检查一个端点是否符合特定的期望,而 k6 为此提供了阈值。
使用阈值编写测试
阈值会检查脚本中所有发出的请求,使用团队设定的服务级别目标(SLOs)作为测试的起点是一个好习惯。以下是一个阈值测试的例子:
import http from 'k6/http';
export const options = {
thresholds: {
http_req_failed: ['rate<0.01'], // http errors should be less than 1%
http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms
},
};
export default function () {
http.get('http://www.acme.com');
}
这个测试会调用acme网站,并检查内置的http_req_failed和http_req_durationHTTP 指标是否满足指定的阈值表达式。这些指标是从脚本中所有发出的请求收集的;在这个例子中,只有一个请求。如果需要,可以使用groups和tags来独立评估 HTTP 请求。
现在我们知道如何编写基本的脚本化测试,让我们看看如何使用options进行扩展。
向测试中添加场景以进行大规模运行
在上一节中,我们提到测试只会发出一个 HTTP 请求。通过使用options,可以以复杂的方式管理默认函数的行为。让我们考虑一个简单的例子,我们创建 100 个 VU,每个 VU 将重复执行默认函数 30 分钟:
import http from 'k6/http';
export const options = {
vus: 100,
duration: '30m'
};
export default function () {
http.get('http://www.acme.com');
}
你可能会注意到,我们使用的是与前一节中创建测试阈值时相同的options常量。options配置选项提供了很多灵活性,用于定义测试的行为。通常需要与每个将运行测试的虚拟用户(VU)共享数据。让我们看看测试生命周期如何管理这些需求。
测试生命周期
k6 测试生命周期分为四个阶段。这些阶段在测试文件的顺序中被明确设置:
-
初始化代码:这是出现在测试脚本顶部、设置代码之前的任何代码。它每个虚拟用户(VU)运行一次,用于加载文件、导入模块、配置测试中使用的选项,以及进行类似操作。
-
export function setup() { } -
export default function (data) { } -
export function teardown (data) { }
现在我们已经很好地理解了如何使用 k6 运行测试,我们需要考虑不同的方式来安装和运行 k6。
安装和运行 k6
k6 以几种包格式提供:
-
Linux(
.rpm和.deb) -
macOS
-
Windows
-
容器化镜像
-
所有平台的独立二进制文件
在所有平台上的安装都非常简单,完整的安装说明可以在 k6 官网找到:k6.io/docs/get-started/installation/。
运行 k6 也非常简单,因为所有过程都可以通过 CLI 启动。这一点通过 --help 标志得到了很好的文档说明:
$ k6 --help
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
Usage:
k6 [command]
Available Commands:
archive Create an archive
cloud Run a test on the cloud
completion Generate the autocompletion script for the specified shell
help Help about any command
inspect Inspect a script or archive
login Authenticate with a service
pause Pause a running test
resume Resume a paused test
run Start a test
scale Scale a running test
stats Show test metrics
status Show test status
version Show application version
k6 run 和 k6 cloud 操作分别用于本地运行测试或通过 k6 云运行测试。以下是使用名为 test.js 的测试文件的一些示例命令:
-
运行单个虚拟用户一次:
k6run test.js -
运行 10 个虚拟用户,并在这些虚拟用户中运行 20 次测试:
k6 run -u 10 -i20 test.js -
在 20 秒内将虚拟用户数(VU)从
0增加到50,保持50VU 数量持续 60 秒,然后在 10 秒内将虚拟用户数降回0:k6 run -u 0 -s 20s:50 -s 60s:50 -s10s:0 test.js
这些命令中的 k6 run 都可以用 k6 cloud 替换,以使用 k6 云运行器,而不是从本地机器运行测试。
现在我们已经了解了如何使用 k6 执行负载测试,让我们总结一下。
总结
在本章中,我们探讨了 Grafana 作为其可观察性平台的一部分提供的两个工具:Pyroscope 和 k6。我们学习了如何搜索 Pyroscope 收集的配置文件数据,以及如何配置客户端以收集这些配置文件数据。我们还学习了如何使用原生语言 SDK 和 Lambda 层为无服务器应用程序对应用程序进行监控。最后,我们探索了新的 Pyroscope 架构,并看到它与 Loki、Mimir 和 Tempo 非常相似。这种新的可扩展性应该为 Pyroscope 提供空间,发展成一个重要的第四种遥测类型,使系统更具可观察性。
使用 k6,我们了解了各种类型的负载或性能测试。我们看到如何使用 JavaScript 语言编写测试,使用检查和阈值来表达应用程序的重要度量。我们了解了如何使用 options 来管理 k6 运行测试的方式,以及如何在脚本中添加正确的数据和功能,以最好地利用测试生命周期。最后,我们了解了安装和运行 k6 的过程,以及简单的操作如何使我们能够将该工具作为 CI/CD 流水线的一部分来连续进行负载测试,验证应用程序的性能是否符合 SLO。
在下一章中,我们将汇集所有工具、API 和知识,理解如何使用 Grafana 最好地支持 DevOps 原则。
第十四章:使用可观察性支持 DevOps 流程
本章将讨论 Grafana 在技术行业的两个不同方面的应用——软件交付和平台操作。
我们将简要介绍DevOps 生命周期,作为宝贵的基础知识。使用这一框架,我们将引导你了解 Grafana 在每个阶段的价值,从而丰富你组织中的软件开发过程。我们鼓励你花时间理解在这个过程中瓶颈所在,并将资源集中在最适合你团队或组织的阶段。
平台操作的典型特点是使用第三方应用程序。这去除了约一半的 DevOps 生命周期,因为这些阶段是由第三方完成的。我们将介绍在部署和操作几种平台时,使用 Grafana 时应考虑的事项。我们将探讨如何从可观察性平台中的数据采集工具收集数据,并考虑在这一业务关键系统发生故障时的灾难规划最佳实践。我们还将关注那些为组织提供持续集成(CI)或持续交付/部署(CD)能力的平台的运营者和用户的特殊需求,因为监控这些平台可能具有挑战性。我们将讨论用于监控数据库、内存数据存储、消息总线和 Web 服务器的资源,涵盖如何高效安装这些工具,以及这些常见工具如何在 Grafana 中提供公开可用的仪表盘供使用。最后,我们将简要介绍这种监控平台模式如何适用于某些安全工具。
本章将涉及技术概念,但并不要求具备单一工具的使用经验,本章应当对任何人都易于理解,无论其背景如何。
在本章中,我们将讨论以下主要主题:
-
介绍 DevOps 生命周期
-
在开发生命周期中使用 Grafana 进行快速反馈
-
使用 Grafana 监控基础设施和平台
介绍 DevOps 生命周期
在我们解释什么是 DevOps 生命周期之前,先来了解一下敏捷、DevOps、DevSecOps 和平台工程的历史。
迭代开发实践早在 1950 年代末期就已使用,但在 1990 年代,几种开发方法应运而生,作为对那些被视为繁重、微观管理、高度规范化且具有较高项目失败风险的开发实践的反应。这些新方法包括快速应用程序开发(RAD)、Scrum、极限编程和特征驱动设计(FDD)。这些方法都出现在敏捷宣言之前,但现在被视为敏捷实践。根据 2001 年发布的《敏捷宣言》,我们更倾向于以下做法:
-
个人与互动优于流程与工具
-
工作软件重于全面文档
-
客户协作重于合同谈判
-
响应变化重于遵循计划
这意味着,虽然右侧的内容有其价值,但我们更看重左侧的内容。
敏捷实践源于开发实践,虽然它们主要聚焦于开发团队,但与运营实践也有很多交集。这些宣言理念激发了对测试驱动开发、持续集成(CI)、持续交付(CD)等实践的浓厚兴趣。
在 2000 年代初,开发实践与运营实践分离的问题受到关注(尽管这些问题在 1980 年代和 1990 年代也曾提出)。这些关注点在 2009 年通过第一次DevOps Days大会得到了汇聚。DevOps 并没有像敏捷一样提出一个中央哲学,但它提出了旨在加速工作软件交付给客户的实践和措施。许多这些实践围绕着让开发人员、测试人员和运营人员更紧密地合作,通常通过将他们聚集在同一个团队中来实现。类似地,采用开发实践,比如使用版本控制系统(例如 Git),使得系统配置等运营问题能够成为整个软件系统共同理解的一部分。
DevOps 有多个分支、扩展和概念。对于那些有兴趣进一步阅读的人,以下是其中的一些:ArchOps、站点可靠性工程(SRE)、DevSecOps、DataOps、12 因子应用或15 因子应用、基础设施即代码(IaC)、配置即代码(CaC)以及GitOps。
亚马逊首席技术官 Werner Vogels 在 2006 年的一句话成为 DevOps 运动的口号:“你构建它,你就运行它。”这句话非常有道理。让设计和开发产品的团队也负责其运维,意味着事件能够更快得到解决,客户反馈能够被及时听取并回应。团队能够更加敏捷!当管理得当并且组织结构合适时,这是一种非常有效的运作方式。然而,正如 Matthew Skelton 和 Manuel Pais 在《团队拓扑学》一书中的分析所示(web.devopstopologies.com/index.html#anti-types),许多反模式可能会出现,并导致组织内的功能失调。这种方法也可能会给开发团队带来巨大的认知负担,使得组织更难应对变化。
你可能会问,为什么我们在解释 DevOps 生命周期是什么时,还要包括这段历史。原因是要提醒你,DevOps 生命周期是一个工具,在大多数组织中,它是多个流程的集合;虽然它们有价值,但不应该比个体和互动更有价值。负责管理面向客户的软件系统的团队,与负责管理平台以支持组织目标的团队,在与可观测性平台的互动方式上会有显著差异。考虑到这一点,让我们看一下 DevOps 生命周期,它为我们提供了一个很好的框架,通过这个框架,我们可以讨论在生命周期中使用可观测性平台的许多方面:

图 14.1 – DevOps 生命周期
重要提示
DevOps 或 DevSecOps 没有明确的定义。DevOps 生命周期本身涵盖了开发和运维,而安全性则包裹在所有这些过程之中(以及更多),如 图 14.1 所示。
让我们逐个了解这个生命周期的每个阶段:
-
代码:这是根据规划阶段提供的规范编写新代码的地方。
-
构建:这一阶段是新代码的构建阶段。
-
测试:在这一阶段,新代码会以各种方式进行测试。
-
发布:在此阶段,代码会被验证为可以部署到生产环境;任何最终的检查或确认都会在这里进行。
-
部署:代码被部署到生产环境。
-
运行:这一阶段是一个持续的阶段;最新发布的版本会在生产环境中运行。
-
监控:从当前在生产环境中运行的发布版本中收集的所有数据,以及任何反馈或用户研究,都被收集并汇总,以便在下一阶段的规划中使用。
-
规划:在此阶段,团队规划产品未来的迭代将包含哪些内容。
-
安全:这是 DevSecOps 方法中团队的持续关注点,所有团队成员都要对其负责。
现在我们已经了解了 DevOps 生命周期,让我们考虑如何在这个生命周期的每个阶段使用 Grafana 工具。
在开发生命周期中使用 Grafana 快速反馈
在本节中,我们将考虑如何在 DevOps 生命周期的每个阶段使用 Grafana 工具。软件开发可能是有风险和昂贵的,可观测性平台也可能很昂贵。因此,利用可观测性平台的数据来降低软件开发的风险和成本,是一项很好的投资。我们将从生命周期的 代码 阶段开始。
代码
要在 DevOps 生命周期中使用 Grafana,系统必须产生有用的数据,这些数据可以帮助理解系统的状态。为此,生命周期中的第一个动作是在 代码 阶段对系统进行 监控。根据我们所处理的系统类型,生成数据的方法可能会有所不同:
-
软件应用程序通过添加库或 SDK 来进行仪器化,这些库或 SDK 会产生与收集数据的团队商定格式的数据。在某些情况下,这甚至可以通过在应用程序中注入仪器化代码来实现,这可能发生在生命周期的部署阶段。组织需要明确这种责任归属。
-
云基础设施或云平台组件将通过收集来自供应商的数据来进行仪器化。
-
本地基础设施或本地平台组件将通过收集由组件供应商支持的格式的数据来进行仪器化。
对于许多系统来说,这可能是所需的一切。然而,也有时组织需要来自系统的自定义数据。添加这样的仪器化操作恰恰属于生命周期中的编码阶段。然而,在考虑此类活动时,重要的是要确保同时考虑规划和测试阶段。这可以通过一些活动来实现,例如达成数据格式和字段定义的一致,并以一种可以在产品未来版本中进行测试的方式实现代码(例如,面向领域的可观察性)。
Grafana 在编码过程中提供的最终帮助是通过直接在开发中的代码上运行。大多数开发者(如果不是所有开发者)会在提交到版本控制仓库之前先在本地运行代码。由于 Grafana 是开源的,非常容易实现一个本地开发环境,该环境可以生成和收集可观察性遥测数据;我们在第三章、第四章、第五章和第六章中探讨实时数据时提供了这种环境的示例。这些丰富的信息可以直接反馈到正在进行的编码过程中。
生命周期的下一个阶段是构建阶段。我们将在接下来的章节中详细讨论如何监控构建,因此这里跳过这一部分。接下来让我们讨论测试阶段。
测试
测试阶段可以涵盖许多不同类型的测试。虽然测试通常由 CI/CD 平台管理,例如使用测试框架或静态分析工具,但 Grafana 中最常见的反馈形式是监控 CI/CD 平台本身。对于那些希望追踪更多信息的组织或团队,另一种方法是将 CI/CD 平台的时间序列数据输出到时间序列数据库(TSDB)中。这些自定义方法往往像复杂的鲁布·戈德堡机器,因此我们提醒您要非常谨慎地评估它对组织的价值,并建议您研究市场,以便了解是否有更合适的产品。
随着测试阶段进入端到端测试,像 k6 这样的工具开始发挥重要作用(我们在第十三章中讨论了这一点)。为这一领域的工具编写出色的可重复测试,亦可为在生命周期的部署阶段运行这些测试提供极具价值的能力,以确认新代码已成功部署。
发布阶段涵盖了从完成测试到将代码发布给客户之间的所有内容。通常,这个阶段包括如获得来自利益相关者或保障团队的部署批准等活动。让我们看看 Grafana 如何提供帮助。
发布
在讨论使用 Grafana 进行发布阶段之前,我们先做一个简短的警告:市场上的许多工具可能更适合某些组织和团队,因此我们建议组织在遇到发布流程问题时,进行一些研究。
Grafana 的最大特点之一,是能够显示产品的新迭代是否符合服务水平目标(SLOs)和服务水平协议(SLAs)。展示这些来自新迭代的指标,尤其是当产品通过如 k6 之类的工具进行负载测试时,是证明新迭代按预期运行的非常有效方式。
另一个可能对某些团队有用的特性,是自动构建包含 HTML 小部件的仪表盘。这可以用于自动生成一个发布仪表盘,并链接到各种工件,例如测试报告、包含功能的工单等。
生命周期的操作阶段与 Grafana 最为相关。我们首先来看一下部署阶段,在此阶段,代码被部署到生产环境中,供客户访问。
部署
部署阶段会发生许多变化,具体使用 Grafana 的方式将取决于系统的部署方式:
-
当应用程序部署到 Kubernetes 集群时,Pods 将被安排终止,同时将启动使用新版本的 Pods。我们可能会看到负责数据库更新的 Pods 被安排终止,以及其他各种方面。当 Grafana 作为 Kubernetes 集群所有遥测数据的存储库时,它可以用于以适合部署团队的方式可视化部署过程,从预建仪表盘到专门为某个应用部署量身定制的仪表盘。
-
当应用程序直接部署到操作系统而非容器化环境时,Grafana 仍提供详细的监控,具有预建的操作系统仪表盘,涵盖常见语言、Web 服务器、数据库、内存数据存储及许多其他工具。
这些方法提供了白盒监控的部署;许多组织还会在部署期间实施黑盒监控。Grafana 在这里也能提供帮助。通过使用Grafana OnCall接收来自可用性监控工具(如 Prometheus 黑盒出口、k6 或 Pingdom)的消息,在部署期间也可以监控这条数据流。
最好的做法是在部署发生时生成注释,这可以通过 API 完成。以下是添加到 OpenTelemetry Collector 部署中并导致事故的注释示例:

图 14.2 – 注释的实际应用
如截图所示,Grafana 将在任何启用了此选项的可视化图表上显示有关部署的上下文信息。注释以线条的形式出现在图表上,当鼠标悬停时会显示信息;这些上下文信息可以被标记。
本质上,CD 平台是代码执行平台,这意味着任何可以编写的操作都可以由 CD 平台执行。我们刚刚讨论了使用仪表盘可视化监控部署。这种方法在部署发生不频繁时效果很好。但当部署变得更为频繁时,投入时间编写部署的各个阶段,监控正在部署的应用程序状态会非常有价值。Loki、Mimir 和 Tempo 都提供查询端点,可以在脚本化的 CD 任务中运行查询。实际上,这将监控仪表盘的工作交给了 CD 管道,如果部署失败,还可以定义回滚步骤。一些常见的使用示例如下:
-
监控应用程序日志中看到的错误率。
-
检查登录操作是否成功。这通常会与冒烟测试相关联,以确保登录事件的发生。
-
检查是否与下游服务的通信受到影响。
如果这些检查失败,可以通过自动化流程快速回滚部署。这种方法大大减少了平均恢复时间(MTTR),确保工程师能够在部署期间专注于更有价值的任务。
利用 Grafana 提供的工具的黄金标准是,在与代码部署相同的部署窗口内,通过 Terraform 部署用于服务的仪表盘的任何更新。采用这种做法可以实现一个容易重复的过程,从本地开发工作通过测试再到生产环境。
虽然令人兴奋,部署阶段并不是代码处于正常运行状态的阶段;那个阶段是运行阶段。我们接下来来看看这个阶段。
运行
操作阶段是产品在客户面前上线的阶段。这个阶段最重要的方面是确保客户得到优质的服务。通过监控 SLO 和 SLA,检查可能发生的错误,响应事件,并帮助客户使用产品,可以实现这一目标。Grafana 主要是一个在操作阶段使用的工具,因此 Grafana 中的大多数工具都面向这个阶段。所有使用 Grafana 的团队都会使用一些关键组件,如仪表盘和警报。能够看到用户如何与产品互动对运营团队(如客户体验或客户支持团队)也是非常有价值的。
我们在第九章中讨论了如何通过Grafana 告警和Grafana 事件与许多系统集成。这一功能在创建详细的事件响应系统时非常有帮助——例如,通过将 Grafana 与 ServiceNow 集成,可以部分或完全自动化事件工单的创建、更新和关闭,甚至可以收集聊天通信,以减少在事件报告中撰写发生情况所需的时间。
我们在第十二章中讨论了如何使用Grafana 前端可观察性;当与分布式追踪正确实现时,该工具可以让面向客户的团队重建单个用户的会话。这使得这些团队能够快速与客户合作,了解他们遇到的前端问题,并将其转化为系统中的追踪路径,以便快速找到问题的根源并将其传递给正确的团队,同时提供易于理解的事件发生信息。
让我们考虑如何使用 Grafana 来监控系统。
监控
和操作阶段一样,监控阶段是使用 Grafana 真正展现其优势的阶段。最大的两个挑战是知道应该使用哪些遥测数据来回答关于产品的问题,以及是否有提供这些遥测数据。虽然列出所有潜在的问题是不可能的,但以下是一些常见的问题,并与最适合回答这些问题的遥测类型进行了关联:
-
我的客户如何与我的产品互动?
最好的回答方式是使用真实用户监控,我们在第十二章中讨论过。这个问题可以涵盖许多类似的问题,比如新功能的采用情况,或者系统中是否有未访问的页面或功能。
-
是否有特定功能比较慢?
这个问题可以通过结合来自度量的请求时间信息与日志中生成的详细应用信息来回答。我们在第四章和第五章中讨论了这些内容。对于有下游依赖关系的应用,这些信息还可以通过追踪数据来补充,正如在第六章中讨论的那样。
-
为什么某个特定功能变慢了?
这个问题通常会通过本地测试来回答,但使用对系统进行持续分析的方式,结合实际或重播的请求,可以显著帮助这一过程。第十三章详细讨论了持续分析。
-
我的应用程序是否按预期运行?
最好的解决方法是为应用建立明确的服务级指标(SLIs)和 SLOs;我们在第九章中概述了如何进行此操作。
-
服务是否符合 SLOs/SLAs?
通常,通过使用度量数据来回答这个问题。然而,一些指标可能是从日志或追踪数据派生的度量——例如,通过日志中看到的错误数量创建一个度量。
-
我的基础设施是否正确扩展?
这个问题将通过从基础设施收集数据来回答。收集方式可能会根据基础设施的类型而有所不同:
-
对于云基础设施,这是通过提供日志、度量,有时还提供追踪数据的集成来完成的。
-
对于本地基础设施,收集方法会有所不同。
我们在第七章中更详细地讨论了这个话题。
-
-
某件事的长期趋势如何?
长期趋势分析的最佳遥测类型是度量,因为它们提供了默认的 13 个月保留期。这意味着此类分析的最佳实践是从你希望跟踪的数据中生成一个度量。
另一种方法是将数据从 Grafana 加载到某种形式的数据仓库中,但这超出了本书的范围。
操作阶段和监控阶段之间的真正区别在于使用 Grafana 的目标。在操作阶段,目标是确保系统对客户正常运行。在监控阶段,目标是了解并记录系统的运行情况,以便为计划阶段提供输入,从而改进系统。让我们以计划阶段来结束对 DevOps 生命周期的讨论。
计划
计划阶段从多个来源获取输入,以帮助团队决定下一个工作的优先级。在监控阶段提出的问题,以及操作阶段中的任何事件或 SLO 违约,都是这些来源的一部分。为了帮助优先排序,通常会考虑以下内容:
-
一个特定事件或潜在改进会影响多少客户?
Grafana 中的日志、度量和追踪可以收集回答此问题所需的数据。这对于那些来自其他地方(如用户反馈)的变更也是适用的。
-
系统中某个组件的容量接近极限时,或者在瓶颈开始引发故障或性能下降之前,还有多少时间可以解决这个问题?
通过使用 k6 进行负载测试,可以在瓶颈变得关键之前,通过突发测试、压力测试,甚至是测试到断点,来识别瓶颈。
DevOps 生命周期非常专注于开发软件的团队。组织通常会使用第三方提供的软件来提供内部平台。这与部署、运营和监控阶段有很多重叠,但让我们更详细地看一下在这些平台中使用可观察性。
使用 Grafana 监控基础设施和平台
与第三方基础设施和平台合作的团队得到 Grafana 和 OpenTelemetry 工具的良好支持。我们将考虑几种主要类型的平台:可观察性、CI、CD、基础设施与资源,以及最后的安全平台。这些平台的部署、运营、监控和计划阶段应该被理解,前一部分提到的这些阶段的要点也适用于这些平台产品。让我们从考虑可观察性平台开始。
可观察性平台
管理可观察性平台的团队有责任提供一个能够展示最佳实践的平台,包括有良好文档的 SLI 和 SLO,易于查找的仪表板,以及可靠的事件管理过程。
有帮助的是,Grafana Dashboards 社区门户提供了许多仪表板,这些仪表板可以非常详细地展示 OpenTelemetry Collector 以及数据如何通过 Collector 流动。决定哪些 Collector 的方面对你的组织最重要,并将其发布,是任何管理可观察性收集的团队都应该采取的步骤。
管理可观察性平台时,一个重要的考虑因素是平台丧失时的灾难管理过程。虽然这种情况不太可能发生,但拥有经过测试的计划总比在平台出现故障时临时想出一个方案要好——这是经过一次非常痛苦的经历后得到的建议。通常,灾难恢复计划可以很简单——例如,在每个集群中创建一个 Prometheus 实例,甚至一个完整的 Grafana 堆栈,将使组织在他们使用的软件即服务(SaaS)平台出现故障时,仍然能够继续运营。
相关的计划应该包括如何控制嘈杂的数据源。将生产数据与其他数据源隔离是最佳实践。有时,嘈杂的数据源的财务或容量成本可能会导致业务中断。这些风险可以通过几种方式来管理,例如撤销 API 密钥、为收集器添加过滤器,甚至采取更极端的措施,如关闭数据源。
接下来,让我们考虑 CI 平台。
CI 平台
CI 平台涉及许多不同的工具,例如 Github Actions、GitLab CI/CD、Jenkins、Azure DevOps、Google Cloud Build 等等。我们认为,CI 平台上最常见的问题是“为什么我的构建失败了?”。为工程师提供调试构建的工具对于这样的平台至关重要。通常,CI 平台本身可以看到这些反馈。然而,对于某些类型的失败,这些反馈可能并不明显,例如一个失败的运行者、一个“吵闹的邻居”或其他问题。在这些情况下,从 CI 平台本身收集的数据非常有用。
由于 CI 平台的性质,数据收集通常需要针对平台进行定制:
-
云供应商提供的平台通常会通过收集来自平台的日志和指标,并使用供应商自己提供的工具(例如,AWS CloudWatch、GCP Operations Suite 或 Azure Monitor)进行处理,然后在适当的情况下将它们发送到 Grafana 实例。
-
其他平台可能需要安装代理。我们在第十三章中讨论了这一过程。作为参考,OpenTelemetry Collector 提供了多种格式,包括 Docker 镜像、Alpine 镜像(APK)、Debian 镜像(
.deb)、Enterprise Linux 镜像(.rpm)以及通用镜像(.tar.gz),这些都包括适用于 macOS(Intel 和 ARM)和 Windows 的可执行文件。Grafana Agent 提供了 Docker 镜像、Debian 镜像(.deb)、Enterprise Linux 镜像(.rpm)、SUSE 镜像、macOS 镜像(通过 Homebrew 支持 Intel 和 ARM)、以及 Windows 安装程序(.exe)。
安装代理后,应该管理配置,以便为平台上进行的集成工作提供最佳支持。我们建议使用在第十章中讨论的自动化工具之一来管理此配置。
日志和指标是主要需要捕获的数据组件,因为 CI 平台通常不需要分布式追踪。团队在向 CI 平台添加可观察性时需要考虑的一件事是,领导团队是否希望跟踪更高层次的业务指标——例如,变更的提前期、缺陷数或类似指标。对于那些想要深入了解这些理念的人,我们建议查看谷歌的DevOps 研究与评估(DORA)团队报告(cloud.google.com/devops/state-of-devops/)。这类考虑通常需要跨多个团队达成一致,因此清晰记录它们的计算和收集方式至关重要。这类数据收集可能会在可观察性工具中进行,也可能不会。最佳实践是将 CI 平台的数据与业务关键工作负载分开。这可以通过专门为 CI 工作负载配置一个独立的 Grafana 堆栈来轻松实现。对于这些系统,也有公开的仪表板可供使用。
现在我们已经看到如何监控 CI 平台,接下来让我们考虑部署平台。
CD 平台
CD 平台通常与 CI 平台有交集;我们将它们视为独立的,因为它们是整体系统的不同方面。这些平台使用像 Jenkins、GitLab CI/CD、AWS CodeDeploy、ArgoCD、FluxCD 等类似的工具进行操作。对于基础设施部署,它们可能还包括 Terraform Cloud、Atlantis 或 Spacelift 等工具。有两类主要的 CD 工具:推送系统和拉取系统。我们将分别讨论它们,因为数据收集过程有所不同。无论使用哪种部署方法,良好集成 Grafana 的一个非常重要的方面是记录 Grafana 中的注释。我们在讨论 DevOps 生命周期的部署阶段时曾详细探讨过这个问题,但这些上下文信息在故障排除时可以节省大量时间,并最终提供更好的客户体验。
Kubernetes 中的拉取系统也使用GitOps这一术语;这类系统通常使用 ArgoCD 或 FluxCD 等工具。由于这些工具被部署到现有的 Kubernetes 集群中,因此可观察性姿态非常简单,因为服务将由集群中现有的收集基础设施进行数据收集。ArgoCD 提供 Prometheus 格式的度量指标,并且有几个公开的仪表板可供使用。还可以通过 Argo 工具组中的其他工具扩展数据收集。FluxCD 也提供 Prometheus 度量指标,并且可以与 kube-state-metrics 一起扩展。该工具还提供日志并生成 Kubernetes 事件。除了 Kubernetes 外,还有其他拉取系统,如 Chef 和 ansible-pull,但由于这些工具的普及度较低,我们在此不讨论它们。
基于推送的 CD 平台有一个或多个中央系统连接到部署目标并运行部署过程。Jenkins 可能是这里的经典例子,但像 GitHub Actions 和 GitLab CI/CD 这样的系统也属于这一类。你可能会注意到,这些工具在我们考虑 CI 平台时也曾提到过。毫不奇怪,这些工具的监控方式是一样的,无论它们是用于集成任务还是交付/部署任务。当这些工具的使用既包括集成任务又包括交付/部署任务时,从安全角度监控平台的行为非常重要,因为这些系统在集成阶段通常会使用第三方库,从而使系统暴露于供应链攻击的风险中。将这种攻击与对生产环境的高级访问结合在一起,可能对组织构成非常真实的威胁。
现在我们已经考虑了如何监控构建和部署软件的平台。接下来让我们考虑一个更广泛的系统群体。我们将在下一部分中讨论数据存储和消息队列系统。
资源平台
我们使用资源平台这个术语来描述一个应用程序可能依赖的后端系统类型。这些可能包括数据库、内存数据存储、消息总线、Web 服务器或类似的系统。这些平台是一个特殊的案例,因为系统的责任可能分布在组织的不同领域。通常,由软件交付团队负责,或者有时由一个集中式团队负责。我们将尽量通过一般性讨论这些工具如何确保可观察性来忽略这种复杂性。
有一些地方可以开始查看如何监控这些系统:
-
OpenTelemetry Collector 贡献的接收器:有很多为各种资源平台提供的贡献接收器模块。部署这些接收器非常简单:
-
在 Kubernetes 中,收集器可以作为服务的旁车部署,或者作为集群或命名空间中的专用代理,负责将遥测数据转发到网关。图 11.5 中展示了一个专用代理的示例,位于 第十一章,该代理用于从 Kubernetes 集群收集指标。
-
在虚拟化或裸金属安装中,需要部署专用的 OpenTelemetry Collector,尽管通常可以在被监控的实例上完成这项部署,并且不会造成性能下降。
-
-
Prometheus 模块:这些是允许 Prometheus 从许多资源平台抓取数据的模块。只需将它们部署到 Prometheus 实例,并配置连接到需要监控的平台即可。
一旦从这些系统收集了指标,Grafana 提供了广泛的预构建公共仪表板。这些仪表板的广泛可用性意味着它的价值实现时间非常好。
需要特别强调的是,为了避免混淆,这种类型的数据收集与将系统用作 Grafana 数据源是不同的。许多这些系统,特别是像 MySQL、PostgreSQL 和 MongoDB 这样的数据库,可以作为 Grafana 的数据源。数据源连接到系统并允许用户查询系统中的数据。而我们在这里讨论的工具连接到系统并从中查询操作性指标。这些指标可以用来提供服务水平目标(SLO)并向其他团队展示系统的运行情况。
安全平台
我们不会深入探讨安全平台,因为它们本身就足以写成一本书。然而,值得注意的是,一些工具,如Falco、Open Policy Agent、kube-bench、Trivy 等,提供了暴露与其操作相关的指标的方法,这些指标可以以某种方式被 Grafana 消耗。
可观测平台和网络安全平台存在非常大的交叉关注点。这两个平台都使用日志数据,这可能导致运行多个代理以收集这些数据。更具成本效益的解决方案可能是这些团队共同开发支持双方操作的数据管道。这样的管道应该被密切监控,因为它可能对组织构成重大风险。
我们现在考虑在软件应用程序生命周期和基础设施及平台管理中使用 Grafana。
概要
在本章中,我们考虑了如何在 DevOps 生命周期中使用 Grafana。您了解了如何在本地环境中部署 Grafana,以加快开发时间,通过即时反馈了解代码性能。我们讨论了测试阶段,您了解了如何使用 k6 等工具提供可重复的优秀测试,甚至可以在应用程序部署时使用。在发布阶段,可以使用 Grafana 向批准您的发布的利益相关者展示应用程序的各个方面。我们看到如何通过利用 SLO 和黑盒监控来降低部署风险。我们还看到了如何使用 Grafana 注释来改善部署的可见性。操作和监控阶段在本书中使用 Grafana 的方式非常相似。您了解了这两个阶段目标的不同之处,操作阶段关注正确的功能,而监控阶段关注如何改善客户体验。最后,我们讨论了如何在软件工具规划阶段使用 Grafana 进行基于数据的讨论。
然后我们考虑了 Grafana 如何与各种类型的平台一起使用。我们向您介绍了如何使用 Grafana 监控您的可观测性平台,有效地演示使用自己的产品或“dogfooding”原则,并作为组织最佳实践的示例。您了解了如何将 Grafana 与 CI/CD 平台配合使用,以便组织中的工程师了解其构建和部署的大量数据。然后,我们讨论了如何从行业中使用的许多系统中获取操作数据,例如数据库、内存数据存储、消息总线和 Web 服务器。您了解到最佳方法是寻找可用的数据收集工具和公开可用的仪表板。我们还看了安全平台,您了解到一些工具还以 Prometheus 或 OpenTelemetry 格式呈现数据,这些数据可以被 Grafana 消费。在这种情况下,还提供预构建的 Grafana 仪表板,大大缩短了使用这些工具的价值时间。
我们已经接近本书的尾声。下一章将介绍最佳实践和故障排除技巧。你将了解数据收集和 Grafana 技术栈的一些具体内容,以及关于可观察性中常见陷阱的通用指导。我们还将讨论一些有趣的未来趋势。
第十五章:故障排除、实施最佳实践及更多 Grafana 操作
我们即将结束《Grafana 可观察性》之旅,因此这是一个很好的时机,回顾一下我们所学到的一些内容。在本章中,我们将回顾数据收集的最佳实践,并探讨故障排除技巧,这些技巧有助于将你的遥测数据导入 Grafana。然后,我们将继续介绍 Grafana 堆栈中的更多最佳实践与故障排除,涵盖遥测后端、警报和仪表盘。我们还将识别可观察性中的一些陷阱并教你如何避免它们。最后,在总结之前,我们将展望未来,探索潜在的趋势。
在本章中,我们将涵盖以下主要主题:
-
数据收集的最佳实践与故障排除
-
Grafana 堆栈的最佳实践与故障排除
-
避免可观察性中的陷阱
-
应用监控的未来趋势
数据收集的最佳实践与故障排除
在本书中,我们反复强调了准备、设定目标和定义需求的重要性。事先进行思考工作是不可低估的,但遗憾的是,它经常被完全忽视。太多次我调查一个公司的可观察性平台时,发现收集代理被随意部署,导致后端接收了所有数据流。这种做法的代价是产生了大量未定义的遥测数据,使得你的工作变得更加困难,并且导致昂贵的运营和存储成本。
在本节中,我们将分享一些数据收集的最佳实践,并提供一些有用的故障排除技巧。让我们首先看看数据收集的准备工作。
数据收集准备
可观察性始于监控和观察系统的需求或愿望,而实现这一点需要数据。然而,过多的数据(以及为了数据而收集数据)可能会破坏系统的可观察性,这也是为什么准备工作如此重要。设定目标时要考虑你想从平台中获得什么,以及它是为谁服务的。与其为假设情况做计划,不如为现实情况做规划。你总是可以以后再做调整,这比事后删减要容易得多。
在第一章中,我们介绍了可观察性角色。你可以利用这些角色来收集平台需求。理想情况下,你应该能够回答以下问题:
-
我的可观察性用户是谁?
-
我希望或已有的日志格式是什么?
-
数据的来源是什么?
-
我们的服务级别****目标(SLOs)需要关注哪些指标?
-
跟踪仪器化能帮助解决可观察性问题吗?
-
我需要哪些数据来构建仪表盘?
这些答案将帮助你确定哪种代理技术最适合你的用例,使用哪些日志格式,以及其他重要决策。
让我们看看我们在数据收集时需要做出的一些决策。
数据收集决策
必须尽早做出几个关键决策,这些决策可能会影响整个可观测性过程。重要的是在开始时花时间做出这些决策,因为以后更改它们会变得更加困难和昂贵。在大多数情况下,你的选择已经有限,只能使用现有数据。不过,这并不妨碍你识别并传达一个新的标准来追求。跨整个组织标准化数据收集提供了一个框架,支持工程师遵守规范。在这里,我们将其中一些因素归类在一起,帮助你处理它们:
-
日志:
-
选择一种可以扩展的日志格式,以便能够快速交付并在以后进行增强。
-
仔细选择标签,考虑 Loki 的性能和基数。在查询时,您始终可以将额外的字段提取为标签。
-
考虑是否可以从日志中创建有价值的度量标准(以最大化价值)。
-
-
度量标准:
-
确定重要的度量标准,丢弃不需要的内容。这也有助于度量基数的管理。如果不能丢弃整个度量标准,至少丢弃一些基数最高的标签会有很大帮助。
-
选择能提供所需数据的协议(请记住,协议之间存在差异,因此要仔细阅读每种协议的文档)。
-
如果使用冗长的度量协议,确保采取保护措施(例如,直方图分桶)以限制对系统的洪水攻击。
-
添加上下文,以便能够将度量标准与追踪信息关联。
-
-
追踪:
-
确保实现并验证跨度和追踪信息的准确性
-
通过缓解策略(采样、过滤和保留)平衡性能和成本的影响。
-
-
仪器化库:
- 充分研究它们。如果你使用的是一个库,确保它能够得到持续维护和支持。
-
遥测采集器:
-
进行概念验证,以验证与您的技术兼容的内容。你不希望由于权限限制而无法选择合适的采集器来进入生产环境。
-
考虑采集技术所提供的支持模型(如果有的话)。
-
从采集器中获取哪些业务需求?
-
现在所有决策都已做出,接下来看看如果你的遥测数据没有显示出来应该怎么做。
调试采集器
在可观测性平台中,可能很难隔离后台接收到的遥测数据的问题,尤其是在通过不同的连接和组件发送数据时。
以下是一些有助于诊断问题的步骤:
-
检查采集器日志中的错误消息
-
寻找 Grafana 拒绝的数据,例如以下内容:
-
样本过旧
-
追踪信息过大
-
数据摄取速率限制
-
-
验证认证凭证(令牌过期和权限)
-
验证遥测数据是如何被摄取的(端口和协议)
-
分析遥测数据是否经过采样或修订
-
确定哪些导出器正在被用来将遥测数据发送到下一阶段
-
验证遥测格式。
-
确认下一个跳跃点并验证其配置。
-
测试简单的网络连接性,并确认防火墙规则或网络策略是否限制了数据流动。
我们现在应该已经在后台获得数据,让我们看看一些使用 Grafana 的最佳实践。
Grafana 技术栈的最佳实践与故障排除
与前一部分一样,准备工作的重要性适用于 Grafana 技术栈,就像适用于任何良好的系统设计一样。你正在做出影响用户、数据和成本的决定。在这一部分中,我们将分享一些为 Grafana 做准备的最佳实践,并提供一些有用的调试技巧。让我们首先看看为你的 Grafana 技术栈做准备的活动。
准备 Grafana 技术栈
在设计你的平台时,考虑你要发送的内容和用户是谁。考虑到你的技术栈,重要的是要关注更广泛的主题,如企业身份验证集成,以及尽力调整你的技术栈规模,并实施监控使用情况的流程。
理想情况下,你希望能够回答以下问题:
-
谁需要使用该平台?
-
他们在哪里使用该平台?
-
是否存在数据保留要求(如果有的话)?
Grafana 技术栈决策
在全面采用 Grafana 技术栈之前,必须做出一些重要决定。并非所有的决定都与可观察性有关;其中一些受地区治理的影响,另一些则是公司政策的要求。越早着手并优先处理这些决定,有助于平台的顺利运行。
在这里,我们将一些因素归类在一起,以帮助你处理它们:
-
架构:
-
你的用例是否需要单一或多个技术栈——例如,数据驻留或开发与生产系统的分离?
-
是否有任何数据受到限制,需要特定权限才能访问,例如个人身份信息(PII)和通用数据保护条例(GDPR)?
-
是否存在需要考虑的全局延迟问题?
-
是否有用户审计要求?
-
-
管理:
-
后台是否可以外包,以减轻管理工作量?
-
在发生事件时,你是否具备及时解决问题的能力?
-
使用基础设施即代码(IaC)是否能提供平台控制?
-
-
身份验证:
-
该平台能否与身份验证提供商集成,从而简化用户管理?
-
你是否有特定团队的权限,可能会与身份提供商产生冲突?
-
-
数据保留:
-
你需要创建数据保留策略,了解为什么需要遥测数据以及保留多长时间。
-
存储指标通常较便宜——你可以通过记录规则从日志中生成这些指标,而不是长期存储更昂贵的日志。
-
调试 Grafana
在你的 Grafana 后台,可能会出现一些问题区域或接触点。以下技术应帮助你重新回到正轨,或者至少提供一个参考点,帮助你进一步调试:
-
curl。 -
group by函数用于减少结果集
如果你正在尝试不同版本的查询,查询历史按钮将为你记住这些查询。
- 问题发现:问题所在并不总是显而易见——除非,当然,有人报告了这些问题。Grafana 提供了一套仪表板来支持你在 Grafana Cloud 上的成功。下面是 Grafana Cloud 仪表板 列表的截图:
![Figure 15.1 – Grafana Cloud Dashboards]()
图 15.1 – Grafana Cloud 仪表板
在诊断 Grafana 数据和仪表板中的问题时,Usage Insights 仪表板可以提供帮助。导航到 Usage Insights – 1 – Overview 仪表板并向下滚动,你将看到三个面板:
-
出现错误的前 10 个仪表板:这个功能会告诉你哪些仪表板遇到了一些形式的错误。
-
出现错误的前 10 个数据源:此功能报告存在问题的 Grafana 数据源。这对诊断查询错误或与后端数据源的通信问题非常有用。
-
出现错误的前 10 名用户:这可以识别在 Grafana 内遇到问题的平台用户。在调查平台稳定性时,这非常有帮助。
这些面板指导你了解遇到的问题,并提供深入其他仪表板的链接,以展示具体错误,帮助诊断。
特别是,Grafana Cloud Billing/Usage 仪表板在展示因达到账户限制而导致样本被拒绝时非常重要。此外,Cardinality management 仪表板有助于突出由于标签值导致问题的地方。
现在让我们来看看在更广泛的可观察性领域中可能遇到的问题。
避免可观察性的陷阱
本书中已经确定了几个你需要坐下来思考的方法。这些考虑因素都有助于你在可观察性平台上的持续成功。现在我们将列出其中的一些,并提供一些需要遵循的指南:
-
将你的平台视为一个不断发展的过程;从基础开始,并在此基础上不断构建,持续回顾你的现状。减少价值实现的时间将确保投资回报得以实现。
-
收集多个客户的需求,然后规划一条能为更多用户提供更多价值的路线图,以确保平台的采用和支持。
-
监控成本,特别关注数据收集阶段,因为这个阶段修复成本较低。利用你的可观察性工具来帮助你。
-
尽早修复基数问题,并制定团队可遵循的标准,以控制问题。此外,你可以应用治理措施,限制不符合标准的数据进入平台。
-
隔离高负载、低价值的环境(特别是性能测试环境),以保护业务关键系统的可观察性。你可以为这些环境构建更便宜、短期的可观察性系统,以控制成本。
-
定义一个 6 个月和 12 个月的路线图。这将帮助你规划并适应行业变化。可观察性发展迅速,新的进展不断涌现;灵活应变将帮助你应对这些变化。
-
监控平台使用情况。Grafana 提供了一些优秀的仪表板,如图 15.1所示,帮助你了解使用情况以及使用方式。此外,你还可以通过改善对收集器环境的监控,提升对整个遥测管道的可视化。
现在让我们展望未来,思考可观察性可能会走向何方。
应用监控的未来趋势
很难不带有个人观点地呈现未来趋势,因此以下观点反映了我对行业发展方向的看法:
-
成本削减:在写作时,许多公司都在积极寻找减少运营支出的途径。在可观察性系统中有很多减少成本的空间,Grafana 正处于这一领域的前沿。请查看以下内容:
-
Grafana Cloud 计费/使用仪表板,用于了解 Grafana Cloud 的开支情况。该仪表板是图 15.1中显示的列表的一部分。
-
自适应指标(
grafana.com/docs/grafana-cloud/cost-management-and-billing/reduce-costs/metrics-costs/control-metrics-usage-via-adaptive-metrics/)用于减少成本的解决方案。 -
日志量探索器(
grafana.com/docs/grafana-cloud/cost-management-and-billing/analyze-costs/logs-costs/analyze-log-ingestion-log-volume-explorer/)用于发现过度日志收集的来源。
-
-
人工智能(AI):人工智能最近已经发展到一个成熟的阶段,很快将成为可观察性平台的关键组成部分。Grafana 最近发布了生成式 AI 功能,用于仪表板面板标题和描述文本,以及事件响应自动摘要。你可以在这里查看和阅读更多内容:
grafana.com/blog/2023/08/28/generative-ai-at-grafana-labs-whats-new-whats-next-and-our-vision-for-the-open-source-community/。就在我们这本书即将出版之际,Grafana 宣布收购了Asserts.ai,将根因分析解决方案引入 Grafana;你可以在这里了解更多:grafana.com/blog/2023/11/14/grafana-labs-acquires-asserts/。 -
工具增强:改进开发者与可观察性之间关系的能力,帮助在开发生命周期早期更轻松地采纳可观察性。Grafana 最近发布了与 VS Code 集成的实时仪表板开发工具:
marketplace.visualstudio.com/items?itemName=Grafana.grafana-vscode。 -
OpenTelemetry 标准成熟度:随着标准达成共识,第三方开发对 OpenTelemetry 的支持增加。供应商中立的解决方案越来越受欢迎,帮助降低总体成本(运营和管理)。
-
收集器管理:以下是一些用于代理技术的配置和控制工具:
-
开放代理管理协议 (
opentelemetry.io/docs/specs/opamp/) 用于远程管理大规模数据收集代理的技术。无需重新部署来阻止度量指标或添加新的接收器。 -
Grafana 代理流程 为 Grafana 代理构建复杂遥测管道提供了新方法。它包括代理管道的可视化,非常适合理解复杂配置。
-
-
平台工程:平台工程的进展将有助于提高可观察性采纳和开发,因为对遥测的依赖不断增加。
现在我们将结束本章及全书。你应该已经具备了实施、排除故障并管理 Grafana 以支持你的可观察性之旅的知识。
总结
在本章中,我们讨论了数据收集和 Grafana 堆栈的最佳实践和故障排除技术。我们还探讨了如何避免可观察性的一些陷阱,并以应用程序监控的未来趋势作为总结。这些章节应该为你提供了能够支持你成功构建可观察性平台的见解,并帮助你更快速、更高效地为用户提供平台价值。现在我们已经完成了《与 Grafana 一起实现可观察性》之旅的最后一章,让我们花点时间回顾一下我们的关键学习成果。
在本书的第一部分,我们介绍了可观察性和 Grafana,并探讨了应用程序和基础设施的仪表化。我们通过在你自己的 Kubernetes 环境中设置 OpenTelemetry 演示应用程序来结束这一部分。
在第二部分,我们介绍了你将遇到的不同遥测类型与 Grafana 的结合——Loki 用于日志,Prometheus(Mimir)用于度量,Tempo 用于跟踪——它们共同构成了LGTM(Loki, Grafana, Tempo, Mimir),你会在 Grafana 网站上随处可见。然后我们探讨了与 Kubernetes(在全书的演示应用中使用的环境)、AWS、GCP 和 Azure 的集成。
在第三部分,我们更多地使用了 Grafana,通过仪表盘展示数据,并建立了一个带警报的事件管理流程。接着,我们探索了用于配置 Grafana 的基础设施即代码(IaC),然后查看了 Grafana 堆栈的架构。
在最后一部分,我们讨论了使用 Grafana 前端观察性进行真实用户监控,使用 Grafana Pyroscope 进行应用程序分析,以及使用 Grafana K6 进行性能测试。我们通过探讨如何通过观察性支持 DevOps 来结束本书,并在本章中分享了一些最佳实践和故障排除技巧。
观察性领域的技术,尤其是与 Grafana 相关的技术发展迅速。希望我们为您提供了一些永恒的方法和技巧,您可以发展这些技能来支持您的观察性工作。当您需要帮助时,您的新朋友——观察性角色,将会随时伸出援手。感谢您让我们成为您旅程的一部分。祝您好运!







浙公网安备 33010602011771号