vlambda博客
学习文章列表

读书笔记《hands-on-infrastructure-monitoring-with-prometheus》故障排除和验证

Troubleshooting and Validation

故障排除本身就是一门艺术,在本章中,我们将提供一些有关如何快速检测和修复问题的有用指南。您将发现公开关键信息的有用端点,了解 promtool、Prometheus 的命令行界面和验证工具,以及如何将其集成到您的日常工作流程中。最后,我们将研究 Prometheus 数据库并收集有关其使用的有见地的信息。

简而言之,本章将涵盖以下主题:

  • The test environment for this chapter
  • Exploring promtool
  • Logs and endpoint validation
  • Analyzing the time series database

The test environment for this chapter

在本章中,我们将专注于 Prometheus 服务器并将部署一个新实例,以便我们可以使用新的测试环境应用本章中介绍的概念。

Deployment

要创建 Prometheus 的新实例,请移至正确的存储库路径:

cd chapter08/

确保没有其他测试环境正在运行并启动本章的环境:

vagrant global-status
vagrant up

您可以使用以下方法验证测试环境的成功部署:

vagrant status

这应该输出以下内容:

Current machine states:

prometheus running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to shut it down forcefully, or you can run `vagrant suspend` to simply suspend the virtual machine. In either case, to restart it again, simply run `vagrant up`.

新实例将可供检查,Prometheus Web 界面可通过 http://192.168.42.10:9090 访问。

您现在可以通过执行以下命令来访问 Prometheus 实例:

vagrant ssh prometheus

现在您已连接到 Prometheus 实例,您可以验证本章中描述的说明。

Cleanup

完成测试后,只需确保您在 chapter08/ 内并执行以下命令:

vagrant destroy -f

不要太担心——如果需要,您可以轻松地再次启动环境。

Exploring promtool

Prometheus 附带了一个非常有用的支持命令行工具,称为 promtool。这个小的 Golang 二进制文件可用于快速执行多个故障排除操作,并包含有用的子命令。

可用的功能可以分为四类,我们将在接下来介绍。

Checks

属于此类别的子命令为用户提供了检查和验证 Prometheus 服务器的多个配置方面和指标标准合规性的能力。以下部分描述了它们的用法。

check config

promtool 提供了几种类型的检查。最有价值的一项是检查 Prometheus 服务器的主要配置文件。

check config 需要一个 Prometheus 主配置文件的路径,并输出其对配置有效性的评估。当出现问题时,此子命令可以告诉用户问题所在:如果是非破坏性问题,例如空的发现文件,它将输出警告但允许 promtool 成功退出;当遇到破坏性错误时,例如不正确的语法,它会输出错误并将检查标记为失败。使用工具返回的退出代码 - 0 表示成功,1 表示失败 - 是确保配置更改不会在重启时破坏 Prometheus 的好方法,应该使用作为飞行前检查。除了主配置文件外,此选项还递归检查任何引用的文件,例如规则文件。

下面的例子说明了它的用法:

vagrant@prometheus:~$ promtool check config /etc/prometheus/prometheus.yml 
Checking /etc/prometheus/prometheus.yml
  SUCCESS: 1 rule files found

Checking /etc/prometheus/first_rules.yml
  SUCCESS: 1 rules found

check rules

检查规则 分析和查明规则配置文件中的错误配置。它允许直接定位特定规则文件,这使您可以测试尚未在主要 Prometheus 配置中引用的文件。此功能在规则文件的开发周期和使用配置管理时验证所述文件中的自动更改时都很方便。我们将在 第 9 章中深入介绍这些概念, 定义警报和记录规则

这是检查规则文件时的预期输出:

vagrant@prometheus:~$ promtool check rules /etc/prometheus/first_rules.yml 
Checking /etc/prometheus/first_rules.yml
  SUCCESS: 1 rules found

check metrics

check metrics 子命令验证传递给它的指标在一致性和正确性方面是否遵循 Prometheus 指南。这在开发周期中很有用,可以确保新仪器符合标准,如果您可以控制新作业是否遵循相同的规则,也可以在自动化中使用它。它期望度量有效负载通过 STDIN 作为输入,因此您可以将文件或 curl 的输出直接通过管道传输到其中。 为了这个例子,我们暴露了 Prometheus 中发生的一个问题 version 2.8.0 :

~$ curl -s http://prometheus:9090/metrics | promtool check metrics
prometheus_tsdb_storage_blocks_bytes_total non-counter metrics should not have "_total" suffix

如您所见,prometheus_tsdb_storage_blocks_bytes_total 指标似乎存在问题。让我们看一下这个特定的指标来解决错误:

~$ curl -s http://prometheus:9090/metrics | grep prometheus_tsdb_storage_blocks_bytes_total
# HELP prometheus_tsdb_storage_blocks_bytes_total The number of bytes that are currently used for local storage by all blocks.
# TYPE prometheus_tsdb_storage_blocks_bytes_total gauge
prometheus_tsdb_storage_blocks_bytes_total 0

在这些旧版本的 Prometheus 中,该指标似乎被声明为量规,但具有 _total 后缀,只能在计数器中使用。

Queries

属于此类别的子命令可以直接从命令行执行 PromQL 表达式。这些查询依赖于 Prometheus 公共 HTTP API。以下主题演示了如何使用它们。

query instant

query instant 子命令允许根据当前时间直接通过命令行查询 Prometheus 服务器。为了使其工作,必须提供 Prometheus 服务器 URL 作为参数,以及要执行的查询,如下所示:

vagrant@prometheus:~$ promtool query instant 'http://prometheus:9090' 'up == 1'
up{instance="prometheus:9090", job="prometheus"} => 1 @[1550609854.042]
up{instance="prometheus:9100", job="node"} => 1 @[1550609854.042]

query range

与前面的子命令类似,query range 可以在指定的时间范围内显示结果。因此,我们必须提供开始和结束 Unix 格式的时间戳,以及查询和 Prometheus 服务器端点。

例如,我们将使用 date 命令定义开始和结束时间戳,生成五分钟前的 Unix 格式时间戳和现在的另一个时间戳。我们还可以使用 --step 标志指定查询的分辨率,在我们的示例中为一分钟。最后,我们放置要执行的 PromQL 表达式,最后得到类似于以下的指令:

vagrant@prometheus:~$ promtool query range --start=$(date -d '5 minutes ago' +'%s') --end=$(date -d 'now' +'%s') --step=1m 'http://prometheus:9090' 'node_network_transmit_bytes_total{device="eth0",instance="prometheus:9100",job="node"}'
node_network_transmit_bytes_total{device="eth0", instance="prometheus:9100", job="node"} =>
139109 @[1551019990]
139251 @[1551020050]
139401 @[1551020110]
139543 @[1551020170]
139693 @[1551020230]
140571 @[1551020290]
The date command available inside our test environment is from GNU coreutils, which differs from the BSD-based one available on macOS. The syntax might not be directly compatible between the two.

query series

使用 query series 子命令,您可以搜索与一组指标名称和标签匹配的所有时间序列。以下是如何使用它:

vagrant@prometheus:~$ promtool query series 'http://prometheus:9090' --match='up' --match='go_info{job="prometheus"}'
{__name__="go_info", instance="prometheus:9090", job="prometheus", version="go1.11.5"}
{__name__="up", instance="prometheus:9090", job="prometheus"}
{__name__="up", instance="prometheus:9100", job="node"}

query labels

使用查询标签,您可以在所有可用指标中搜索特定标签并返回附加到它的所有可能值;例如:

vagrant@prometheus:~$ promtool query labels 'http://prometheus:9090' 'mountpoint'
/
/run
/run/lock
/run/user/1000
/vagrant
/var/lib/lxcfs

Debug

属于此类别的子命令允许从正在运行的 Prometheus 服务器中提取调试数据,以便对其进行分析。接下来我们将演示如何使用它们。

debug pprof

Prometheus 服务器与大多数用 Go 编写的严肃软件一样,使用标准库中名为 pprof 的包进行检测,该包使用特定格式提供运行时分析信息。以这种格式生成的文件随后可以由具有相同名称 (pprof) 的命令行工具读取,该工具使用它们来生成分析数据的报告和可视化。 promtool 提供了 debug pprof 子命令,我们可以在以下代码段中看到它的作用:

vagrant@prometheus:~$ promtool debug pprof 'http://prometheus:9090'
collecting: http://prometheus:9090/debug/pprof/profile?seconds=30
collecting: http://prometheus:9090/debug/pprof/block
collecting: http://prometheus:9090/debug/pprof/goroutine
collecting: http://prometheus:9090/debug/pprof/heap
collecting: http://prometheus:9090/debug/pprof/mutex
collecting: http://prometheus:9090/debug/pprof/threadcreate
collecting: http://prometheus:9090/debug/pprof/trace?seconds=30
Compiling debug information complete, all files written in "debug.tar.gz".

当我们提取上一个命令生成的存档时,我们可以看到几个文件:

vagrant@prometheus:~$ tar xzvf debug.tar.gz 
cpu.pb
block.pb
goroutine.pb
heap.pb
mutex.pb
threadcreate.pb
trace.pb

使用 pprof,我们可以生成转储的图像,我们可以在下一个片段中观察到:

vagrant@prometheus:~$ pprof -svg heap.pb > /vagrant/cache/heap.svg
测试环境自带 pprof 命令行工具可以使用了。有关如何构建和部署它的更多信息,请访问 https://github.com/google/pprof

在您的主机上,在 ./cache/ 路径下的代码存储库中(相对于存储库根目录),您现在应该有一个名为 heap.svg,可以通过浏览器打开进行检查。以下屏幕截图显示了您在查看前面示例生成的文件时可能会看到的内容:

读书笔记《hands-on-infrastructure-monitoring-with-prometheus》故障排除和验证
Figure 8.1: Example of a heap map generated by pprof

debug metrics

此子命令将提供的 Prometheus 实例公开的指标下载到压缩存档中。 debug metrics 并不常用,因为 /metrics Prometheus 端点可供任何能够运行此命令的人使用;它的存在是为了在被要求时更容易将 Prometheus 实例的当前状态提供给外部协助(例如 Prometheus 维护者)。该子命令可以按如下方式使用:

vagrant@prometheus:~$ promtool debug metrics 'http://prometheus:9090'
collecting: http://prometheus:9090/metrics
Compiling debug information complete, all files written in "debug.tar.gz".

vagrant@prometheus:~$ tar xzvf debug.tar.gz 
metrics.txt

vagrant@prometheus:~$ tail -n 5 metrics.txt 
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 284
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0

debug all

此选项将先前的调试子命令聚合为一条指令,如下例所示:

vagrant@prometheus:~$ promtool debug all 'http://prometheus:9090'
collecting: http://prometheus:9090/debug/pprof/threadcreate
collecting: http://prometheus:9090/debug/pprof/profile?seconds=30
collecting: http://prometheus:9090/debug/pprof/block
collecting: http://prometheus:9090/debug/pprof/goroutine
collecting: http://prometheus:9090/debug/pprof/heap
collecting: http://prometheus:9090/debug/pprof/mutex
collecting: http://prometheus:9090/debug/pprof/trace?seconds=30
collecting: http://prometheus:9090/metrics
Compiling debug information complete, all files written in "debug.tar.gz".

Tests

promtool 最近获得了针对定义的记录和警报规则运行单元测试的能力。在您可能需要检查表达式是否匹配以前从未发生过的某些条件的情况下,此功能非常有用,因此很难确保它们在时机成熟时会起作用。此子命令称为 test rules,它采用一个或多个测试文件作为参数。稍后我们将深入探讨此功能,当我们解决如何最好地利用 第 9 章定义警报和记录规则

Logs and endpoint validation

在接下来的部分中,我们将介绍几个有用的 HTTP 端点和服务日志,它们对于解决 Prometheus 实例的问题非常重要。

Endpoints

检查 Prometheus 是否启动并运行通常非常简单,因为它遵循大多数云原生应用程序用于服务健康的约定:一个端点检查服务是否健康,另一个端点检查它是否准备好开始处理传入请求。对于过去使用或曾经使用过 Kubernetes 的人来说,这些可能听起来很熟悉;事实上,Kubernetes 也使用这些约定来评估容器是否需要重新启动(例如,应用程序是否死锁并停止响应健康探测)以及是否可以开始向容器发送流量。在 Prometheus 中,这些是 /-/healthy/-/ready 端点。

您可以通过在测试环境中运行以下命令并检查它们的输出以及它们的 HTTP 状态代码来自己尝试这些端点:

vagrant@prometheus:~$ curl -w "%{http_code}\n" http://localhost:9090/-/healthy
Prometheus is Healthy.
200

vagrant@prometheus:~$ curl -w "%{http_code}\n" http://localhost:9090/-/ready
Prometheus is Ready.
200
In traditional infrastructure, it is usual to use the readiness endpoint as the backend health probe when using load balancers in front of a set of Prometheus instances, as only one health check can be configured. By using the readiness endpoint, traffic is only routed to an instance ready to accept it.

此外,Prometheus 公开了一个 /debug/pprof/ 端点,由 promtool debug pprof 命令使用,如上一节所示。此端点还公开了一个可导航的 Web UI,可以在其中查阅 pprof 调试信息,例如当前的 goroutine 及其堆栈跟踪、堆分配、内存分配等:

读书笔记《hands-on-infrastructure-monitoring-with-prometheus》故障排除和验证
Figure 8.2: Information available on the Prometheus server/debug/pprof endpoint

Logs

与大多数当前软件相比,Prometheus 日志记录非常简洁。这是 Prometheus 维护人员非常有意识的努力,因为无关的日志记录可能会导致性能问题。此外,支持不同的日志流(例如应用程序日志、访问日志和慢查询日志)而不只是将其全部写入标准输出 - 从而使用其他类型的日志向应用程序日志发送垃圾邮件 - 将迫使 Prometheus 明确支持写入文件,这在云原生环境中是不可取的。话虽如此,您可以通过设置 --log.level 标志来配置 Prometheus 以增加应用程序日志的详细程度。例如,失败的抓取被认为是正常的操作行为,因此不会出现在日志中;但是,可以通过将日志详细程度增加到 debug 日志级别来记录它们。

本章测试环境中的 Prometheus 实例已经配置了日志级别设置为调试。您可以通过运行以下命令来确认这一点:

vagrant@prometheus:~$ sudo systemctl cat prometheus.service

相关部分应设置以下标志:

ExecStart=/usr/bin/prometheus \
    --log.level=debug \
    --config.file=/etc/prometheus/prometheus.yml \
    --storage.tsdb.path=/var/lib/prometheus/data \
    --web.console.templates=/usr/share/prometheus/consoles \
    --web.console.libraries=/usr/share/prometheus/console_libraries

所以,现在我们可以看到当一次抓取失败时会发生什么。为此,我们可以在测试环境中停止 node_exporter 服务并查看 Prometheus 日志:

vagrant@prometheus:~$ sudo service node-exporter stop
vagrant@prometheus:~$ sudo journalctl -fu prometheus | grep debug
Feb 23 15:28:14 prometheus prometheus[1438]: level=debug ts=2019-02-23T15:28:14.44856006Z caller=scrape.go:825 component="scrape manager" scrape_pool=node target=http://prometheus:9100/metrics msg="Scrape failed" err="Get http://prometheus:9100/metrics: dial tcp 192.168.42.10:9100: connect: connection refused"
Feb 23 15:28:29 prometheus prometheus[1438]: level=debug ts=2019-02-23T15:28:29.448826505Z caller=scrape.go:825 component="scrape manager" scrape_pool=node target=http://prometheus:9100/metrics msg="Scrape failed" err="Get http://prometheus:9100/metrics: dial tcp 192.168.42.10:9100: connect: connection refused"

Analyzing the time series database

Prometheus 服务器的一个关键组件是它的时间序列数据库。能够分析该数据库的使用情况对于检测系列流失和基数问题至关重要。在这种情况下,流失是指变得陈旧的时间序列(例如,从原始目标停止收集或序列从一次刮到下一次消失),然后开始收集具有稍微不同身份的新序列。一个常见的流失示例与 Kubernetes 应用程序部署有关,其中 pod 实例 IP 地址发生变化,使以前的时间序列过时,并用新的时间序列替换它。这会影响查询时的性能,因为返回的样本可能没有相关性。

值得庆幸的是,Prometheus 数据库的源代码中有一个不起眼的工具,可以分析其数据,并恰当地命名为 tsdb

你可以找到源代码 tsdb 工具位于 https://github.com/prometheus/tsdb/。它可以通过运行轻松构建 在安装了正确 Go 工具链的系统上获取 github.com/prometheus/tsdb/cmd/tsdb

Using the tsdb tool

tsdb 工具可以针对 Prometheus 的整个数据库或仅针对特定数据块运行,并输出有关该数据健康状况的有用信息。要运行此工具,我们必须确保 Prometheus 服务器已停止:

vagrant@prometheus:~$ sudo systemctl stop prometheus

我们将运行针对 Prometheus 数据库路径的 tsdb 工具。为简洁起见,我们将每个部分的输出限制为三个条目。如果没有将块名称指定为参数,则将使用最后一个可用的名称:

vagrant@prometheus:~$ sudo tsdb analyze --limit=3 /var/lib/prometheus/data/

输出分为几个部分。在标题中,我们可以找到该块的摘要,包括以下内容:

  • Its full path location
  • The block duration span, which, in standard Prometheus deployments defaults to two hours
  • The number of series and label names contained in the block
  • Statistics regarding the number of index entries

在这里,我们可以看到上一条指令生成的输出:

Block path: /var/lib/prometheus/data/01D48RFXXF27F91FVNGZ107JCK
Duration: 2h0m0s
Series: 819
Label names: 40
Postings (unique label pairs): 592
Postings entries (total label pairs): 3164

虽然流失在我们的测试环境中并不是真正的问题,但我们可以看到检测到哪些标签对与产生流失的关联度最高:

Label pairs most involved in churning:
112 job=node
112 instance=prometheus:9100
111 instance=prometheus:9090

接下来,我们可以找到流失率最高的标签名称:

Label names most involved in churning:
224 instance
224 __name__
224 job

在标签名称流失之后,我们会看到最常见的标签对:

Most common label pairs:
413 job=node
413 instance=prometheus:9100
406 instance=prometheus:9090

最后,我们到达高基数部分,从标签开始:

Highest cardinality labels:
394 __name__
66 le
30 collector
__name__ 是存储度量名称的内部标签,因此在一个健康的 Prometheus 系统中,它被视为具有最高基数的标签是正常的。请记住,这并不意味着指标名称不能被错误地用作标签(例如,使用 ID 为指标名称添加后缀),因此请务必注意基数的突然增加。

最后,我们找到有关指标名称的统计信息:

Highest cardinality metric names:
30 node_scrape_collector_duration_seconds
30 node_scrape_collector_success
20 prometheus_http_request_duration_seconds_bucket
The preceding statistics are collected from a two hour block. This, however, can also be queried for a given moment via the expression browser using a query similar to topk(3, count({__name__=~".+"}) by (__name__)).

如前所述,您可以选择不同的块进行分析:

vagrant@prometheus:~$ ls -l /var/lib/prometheus/data/
total 28
drwxr-xr-x 3 prometheus prometheus 4096 Feb 21 21:15 01D45Z3QCP8D6135QNS4MEPJEK/
drwxr-xr-x 3 prometheus prometheus 4096 Feb 21 21:15 01D486GRJTNYJH1RM0F2F4Q9TR/
drwxr-xr-x 4 prometheus prometheus 4096 Feb 21 21:15 01D48942G83N129W5FKQ5B3XCH/
drwxr-xr-x 4 prometheus prometheus 4096 Feb 21 21:15 01D48G04625Y6AKQ3Z63YJVNTQ/
drwxr-xr-x 3 prometheus prometheus 4096 Feb 21 21:15 01D48G048ECAR9GZ7QY1Q8SQ6Z/
drwxr-xr-x 4 prometheus prometheus 4096 Feb 21 21:15 01D48RFXXF27F91FVNGZ107JCK/
-rw-r--r-- 1 prometheus prometheus 0 Feb 19 23:16 lock
drwxr-xr-x 2 prometheus prometheus 4096 Feb 19 23:16 wal/

vagrant@prometheus:~$ sudo tsdb analyze /var/lib/prometheus/data 01D486GRJTNYJH1RM0F2F4Q9TR

tsdb 报告的好处在于,它可以更深入地了解指标和标签的使用方式,并针对其目标确定要探索和验证的优秀候选者。

Summary

在本章中,我们有机会尝试了一些有用的工具来解决和分析 Prometheus 配置问题和性能。我们从 promtool 开始,浏览了所有可用的选项;然后,我们使用了几个端点和日志来确保一切都按预期工作。最后,我们描述了 tsdb 工具,以及如何使用它来解决和查明普罗米修斯数据库中的基数以及指标和标签的流失问题。

我们现在可以进入记录和警报规则,这将在下一章中介绍。

Questions

  1. How can you validate whether the main Prometheus configuration file has an issue?
  2. How can you assess whether metrics exposed by a target are up to Prometheus standards?
  3. Using promtool, how would you perform an instant query?
  4. How can you find all the label values being used?
  5. How do you enable debug logs on the Prometheus server?
  6. What's the difference between ready and healthy endpoints?
  7. How can you find the churn of labels on an old block of Prometheus data?

Further reading