监控新星 | 实战Prometheus搭建监控系统

程序源代码

共 22558字,需浏览 46分钟

 ·

2021-04-28 23:42

点击上方蓝色字体,选择“设为星标
回复”资源“获取更多资源

Prometheus是一款基于时序数据库的开源监控告警系统,说起Prometheus则不得不提SoundCloud,这是一个在线音乐分享的平台,类似于做视频分享的YouTube,由于他们在微服务架构的道路上越走越远,出现了成百上千的服务,使用传统的监控系统StatsD和Graphite存在大量的局限性,于是他们在2012年开始着手开发一套全新的监控系统。Prometheus的原作者是Matt T. Proud,他也是在2012年加入SoundCloud的,实际上,在加入SoundCloud之前,Matt一直就职于Google,他从Google的集群管理器Borg和它的监控系统Borgmon中获取灵感,开发了开源的监控系统Prometheus,和Google的很多项目一样,使用的编程语言是Go。

很显然,Prometheus作为一个微服务架构监控系统的解决方案,它和容器也脱不开关系。早在2006年8月9日,Eric Schmidt在搜索引擎大会上首次提出了云计算(Cloud Computing)的概念,在之后的十几年里,云计算的发展势如破竹。在2013年,Pivotal的Matt Stine又提出了云原生(Cloud Native)的概念,云原生由微服务架构、DevOps和以容器为代表的敏捷基础架构组成,帮助企业快速、持续、可靠、规模化地交付软件。为了统一云计算接口和相关标准,2015年7月,隶属于Linux基金会的云原生计算基金会(CNCF,Cloud Native Computing Foundation)应运而生。第一个加入CNCF的项目是Google的Kubernetes,而Prometheus是第二个加入的(2016 年)。

目前Prometheus已经广泛用于Kubernetes集群的监控系统中,对Prometheus的历史感兴趣的同学可以看看SoundCloud的工程师Tobias Schmidt在2016年的PromCon大会上的演讲:The History of Prometheus at SoundCloud。


一、Prometheus概述

我们在SoundCloud的官方博客中可以找到一篇关于他们为什么需要新开发一个监控系统的文章Prometheus: Monitoring at SoundCloud,在这篇文章中,他们介绍到,他们需要的监控系统必须满足下面四个特性:
  • A multi-dimensional data model, so that data can be sliced and diced at will, along dimensions like instance, service, endpoint, and method.
  • Operational simplicity, so that you can spin up a monitoring server where and when you want, even on your local workstation, without setting up a distributed storage backend or reconfiguring the world.
  • Scalable data collection and decentralized architecture, so that you can reliably monitor the many instances of your services, and independent teams can set up independent monitoring servers.
  • Finally, a powerful query language that leverages the data model for meaningful alerting (including easy silencing) and graphing (for dashboards and for ad-hoc exploration).
简单来说,就是下面四个特性:
  • 多维度数据模型

  • 方便的部署和维护

  • 灵活的数据采集

  • 强大的查询语言

实际上,多维度数据模型和强大的查询语言这两个特性,正是时序数据库所要求的,所以Prometheus不仅仅是一个监控系统,同时也是一个时序数据库。那为什么Prometheus不直接使用现有的时序数据库作为后端存储呢?这是因为SoundCloud不仅希望他们的监控系统有着时序数据库的特点,而且还需要部署和维护非常方便。纵观比较流行的时序数据库(参见下面的附录),他们要么组件太多,要么外部依赖繁重,比如:Druid有Historical、MiddleManager、Broker、Coordinator、Overlord、Router一堆的组件,而且还依赖于ZooKeeper、Deep storage(HDFS或S3等),Metadata store(PostgreSQL或MySQL),部署和维护起来成本非常高。而Prometheus采用去中心化架构,可以独立部署,不依赖于外部的分布式存储,你可以在几分钟的时间里就可以搭建出一套监控系统。
此外,Prometheus数据采集方式也非常灵活。要采集目标的监控数据,首先需要在目标处安装数据采集组件,这被称之为Exporter,它会在目标处收集监控数据,并暴露出一个HTTP接口供Prometheus查询,Prometheus通过Pull的方式来采集数据,这和传统的Push模式不同。不过Prometheus也提供了一种方式来支持Push模式,你可以将你的数据推送到Push Gateway,Prometheus通过Pull 的方式从Push Gateway获取数据。目前的Exporter已经可以采集绝大多数的第三方数据,比如Docker、HAProxy、StatsD、JMX等等,官网有一份Exporter的列表。
除了这四大特性,随着Prometheus的不断发展,开始支持越来越多的高级特性,比如:服务发现,更丰富的图表展示,使用外部存储,强大的告警规则和多样的通知方式。下图是 Prometheus 的整体架构图:

从上图可以看出,Prometheus生态系统包含了几个关键的组件:Prometheus server、Pushgateway、Alertmanager、Web UI等,但是大多数组件都不是必需的,其中最核心的组件当然是Prometheus server,它负责收集和存储指标数据,支持表达式查询,和告警的生成。接下来我们就来安装Prometheus server。

二、安装Prometheus server

Prometheus可以支持多种安装方式,包括Docker、Ansible、Chef、Puppet、Saltstack等。下面介绍最简单的两种方式,一种是直接使用编译好的可执行文件,开箱即用,另一种是使用Docker镜像,更多的安装方式可以参考这里。(https://love2.io/@1046102779/doc/prometheus/introductions/install.md)

2.1 开箱即用

首先从 官网的下载页面 获取Prometheus的最新版本和下载地址,目前最新版本是2.4.3(2018年10月),执行下面的命令下载并解压:
$ wget https://github.com/prometheus/prometheus/releases/download/v2.4.3/prometheus-2.4.3.linux-amd64.tar.gz$ tar xvfz prometheus-2.4.3.linux-amd64.tar.gz
然后切换到解压目录,检查Prometheus版本:
$ cd prometheus-2.4.3.linux-amd64$ ./prometheus --versionprometheus, version 2.4.3 (branch: HEAD, revision: 167a4b4e73a8eca8df648d2d2043e21bdb9a7449)  build user:       root@1e42b46043e9  build date:       20181004-08:42:02  go version:       go1.11.1
运行Prometheus server:
$ ./prometheus --config.file=prometheus.yml
2.2 使用Docker镜像
使用Docker安装Prometheus更简单,运行下面的命令即可:
$ sudo docker run -d -p 9090:9090 prom/prometheus
一般情况下,我们还会指定配置文件的位置:
$ sudo docker run -d -p 9090:9090 \    -v ~/docker/prometheus/:/etc/prometheus/ \    prom/prometheus
我们把配置文件放在本地~/docker/prometheus/prometheus.yml,这样可以方便编辑和查看,通过-v参数将本地的配置文件挂载到/etc/prometheus/位置,这是prometheus在容器中默认加载的配置文件位置。如果我们不确定默认的配置文件在哪,可以先执行上面的不带-v参数的命令,然后通过docker inspect命名看看容器在运行时默认的参数有哪些(下面的Args参数):
$ sudo docker inspect 0c[...]"Id": "0c4c2d0eed938395bcecf1e8bb4b6b87091fc4e6385ce5b404b6bb7419010f46","Created": "2018-10-15T22:27:34.56050369Z","Path": "/bin/prometheus","Args": ["--config.file=/etc/prometheus/prometheus.yml","--storage.tsdb.path=/prometheus","--web.console.libraries=/usr/share/prometheus/console_libraries","--web.console.templates=/usr/share/prometheus/consoles"        ],[...]

2.3 配置Prometheus

正如上面两节看到的,Prometheus有一个配置文件,通过参数--config.file来指定,配置文件格式为YAML。我们可以打开默认的配置文件prometheus.yml看下里面的内容:
/etc/prometheus $ cat prometheus.yml # my global configglobal:scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.  # scrape_timeout is set to the global default (10s).
# Alertmanager configurationalerting:alertmanagers:- static_configs:- targets: # - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.rule_files: # - "first_rules.yml" # - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:# Here it's Prometheus itself.scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.- job_name: 'prometheus'
# metrics_path defaults to '/metrics' # scheme defaults to 'http'.
static_configs:- targets: ['localhost:9090']
Prometheus 默认的配置文件分为四大块:
  • global块:Prometheus的全局配置,比如scrape_interval表示Prometheus多久抓取一次数据,evaluation_interval表示多久检测一次告警规则;

  • alerting块:关于Alertmanager的配置,这个我们后面再看;

  • rule_files块:告警规则,这个我们后面再看;

  • scrape_config 块:这里定义了Prometheus要抓取的目标,我们可以看到默认已经配置了一个名称为prometheus的job,这是因为Prometheus在启动的时候也会通过HTTP接口暴露自身的指标数据,这就相当于Prometheus自己监控自己,虽然这在真正使用Prometheus时没啥用处,但是我们可以通过这个例子来学习如何使用Prometheus;可以访问http://localhost:9090/metrics查看Prometheus暴露了哪些指标;

更多的配置参数可以参考这里(https://prometheus.io/docs/prometheus/latest/configuration/configuration/)。

三、学习PromQL

通过上面的步骤安装好Prometheus之后,我们现在可以开始体验Prometheus了。Prometheus提供了可视化的Web UI方便我们操作,直接访问http://localhost:9090/即可,它默认会跳转到Graph页面:

第一次访问这个页面可能会不知所措,我们可以先看看其他菜单下的内容,比如:Alerts展示了定义的所有告警规则,Status可以查看各种Prometheus的状态信息,有Runtime & Build Information、Command-Line Flags、Configuration、Rules、Targets、Service Discovery等等。
实际上Graph页面才是Prometheus最强大的功能,在这里我们可以使用Prometheus提供的一种特殊表达式来查询监控数据,这个表达式被称为PromQL(Prometheus Query Language)。通过PromQL不仅可以在Graph页面查询数据,而且还可以通过Prometheus提供的HTTP API来查询。查询的监控数据有列表和曲线图两种展现形式(对应上图中Console和Graph这两个标签)。
我们上面说过,Prometheus自身也暴露了很多的监控指标,也可以在Graph页面查询,展开Execute按钮旁边的下拉框,可以看到很多指标名称,我们随便选一个,譬如:promhttp_metric_handler_requests_total,这个指标表示/metrics页面的访问次数,Prometheus就是通过这个页面来抓取自身的监控数据的。在Console标签中查询结果如下:

上面在介绍Prometheus的配置文件时,可以看到scrape_interval参数是15s,也就是说Prometheus每15s访问一次/metrics页面,所以我们过15s刷新下页面,可以看到指标值会自增。在Graph标签中可以看得更明显:

3.1 数据模型

要学习PromQL,首先我们需要了解下Prometheus的数据模型,一条Prometheus数据由一个指标名称(metric)和N个标签(label,N>=0)组成的,比如下面这个例子:
promhttp_metric_handler_requests_total{code="200",instance="192.168.0.107:9090",job="prometheus"} 106
这条数据的指标名称为promhttp_metric_handler_requests_total,并且包含三个标签codeinstancejob,这条记录的值为106。上面说过,Prometheus是一个时序数据库,相同指标相同标签的数据构成一条时间序列。如果以传统数据库的概念来理解时序数据库,可以把指标名当作表名,标签是字段,timestamp是主键,还有一个float64类型的字段表示值(Prometheus里面所有值都是按float64存储)。
这种数据模型和OpenTSDB的数据模型是比较类似的,详细的信息可以参考官网文档Data model。另外,关于指标和标签的命名,官网有一些指导性的建议,可以参考 Metric and label naming 。(https://prometheus.io/docs/practices/naming/)
虽然Prometheus里存储的数据都是float64的一个数值,但如果我们按类型来分,可以把Prometheus的数据分成四大类:
  • Counter

  • Gauge

  • Histogram

  • Summary

Counter用于计数,例如:请求次数、任务完成数、错误发生次数,这个值会一直增加,不会减少。Gauge就是一般的数值,可大可小,例如:温度变化、内存使用变化。Histogram是直方图,或称为柱状图,常用于跟踪事件发生的规模,例如:请求耗时、响应大小。它特别之处是可以对记录的内容进行分组,提供count和sum的功能。Summary和Histogram十分相似,也用于跟踪事件发生的规模,不同之处是,它提供了一个quantiles的功能,可以按百分比划分跟踪的结果。例如:quantile取值0.95,表示取采样值里面的95%数据。更多信息可以参考官网文档Metric types(https://prometheus.io/docs/concepts/metric_types/),Summary 和Histogram的概念比较容易混淆,属于比较高阶的指标类型,可以参考Histograms and summaries (https://prometheus.io/docs/practices/histograms/)这里的说明。
这四种类型的数据只在指标的提供方作区分,也就是上面说的Exporter,如果你需要编写自己的Exporter或者在现有系统中暴露供Prometheus抓取的指标,你可以使用Prometheus client libraries(https://prometheus.io/docs/instrumenting/clientlibs/),这个时候你就需要考虑不同指标的数据类型了。如果你不用自己实现,而是直接使用一些现成的Exporter,然后在Prometheus里查查相关的指标数据,那么可以不用太关注这块,不过理解Prometheus的数据类型,对写出正确合理的PromQL也是有帮助的。

3.2 PromQL入门

我们从一些例子开始学习PromQL,最简单的PromQL就是直接输入指标名称,比如:
# 表示 Prometheus 能否抓取 target 的指标,用于 target 的健康检查up
这条语句会查出Prometheus抓取的所有target当前运行情况,譬如下面这样:
up{instance="192.168.0.107:9090",job="prometheus"}    1up{instance="192.168.0.108:9090",job="prometheus"}    1up{instance="192.168.0.107:9100",job="server"}    1up{instance="192.168.0.108:9104",job="mysql"}    0
也可以指定某个label来查询:
up{job="prometheus"}
这种写法被称为Instant vector selectors,这里不仅可以使用=号,还可以使用!==~!~,比如下面这样:
up{job!="prometheus"}up{job=~"server|mysql"}up{job=~"192\.168\.0\.107.+"}
=~ 是根据正则表达式来匹配,必须符合RE2的语法。
和Instant vector selectors相应的,还有一种选择器,叫做Range vector selectors,它可以查出一段时间内的所有数据:
http_requests_total[5m]
这条语句查出5分钟内所有抓取的HTTP请求数,注意它返回的数据类型是Range vector,没办法在Graph上显示成曲线图,一般情况下,会用在Counter类型的指标上,并和rate()irate()函数一起使用(注意rate和irate的区别)。
# 计算的是每秒的平均值,适用于变化很慢的 counter# per-second average rate of increase, for slow-moving countersrate(http_requests_total[5m])
# 计算的是每秒瞬时增加速率,适用于变化很快的 counter# per-second instant rate of increase, for volatile and fast-moving countersirate(http_requests_total[5m])
此外,PromQL还支持countsumminmaxtopk等 聚合操作,还支持rateabsceilfloor等一堆的 内置函数,更多的例子,还是上官网学习吧。如果感兴趣,我们还可以把PromQL和SQL做一个对比,会发现PromQL语法更简洁,查询性能也更高。

3.3 HTTP API

我们不仅仅可以在Prometheus的Graph 页面查询PromQL,Prometheus还提供了一种HTTP API的方式,可以更灵活的将PromQL整合到其他系统中使用,譬如下面要介绍的Grafana,就是通过Prometheus的HTTP API来查询指标数据的。实际上,我们在Prometheus的Graph页面查询也是使用了HTTP API。
我们看下Prometheus的HTTP API官方文档,它提供了下面这些接口:
  • GET /api/v1/query

  • GET /api/v1/query_range

  • GET /api/v1/series

  • GET /api/v1/label/<label_name>/values

  • GET /api/v1/targets

  • GET /api/v1/rules

  • GET /api/v1/alerts

  • GET /api/v1/targets/metadata

  • GET /api/v1/alertmanagers

  • GET /api/v1/status/config

  • GET /api/v1/status/flags

从Prometheus v2.1开始,又新增了几个用于管理TSDB的接口:
  • POST /api/v1/admin/tsdb/snapshot

  • POST /api/v1/admin/tsdb/delete_series

  • POST /api/v1/admin/tsdb/clean_tombstones


四、安装 Grafana

虽然Prometheus提供的Web UI也可以很好的查看不同指标的视图,但是这个功能非常简单,只适合用来调试。要实现一个强大的监控系统,还需要一个能定制展示不同指标的面板,能支持不同类型的展现方式(曲线图、饼状图、热点图、TopN等),这就是仪表盘(Dashboard)功能。因此Prometheus开发了一套仪表盘系统PromDash,不过很快这套系统就被废弃了,官方开始推荐使用Grafana来对Prometheus的指标数据进行可视化,这不仅是因为Grafana的功能非常强大,而且它和Prometheus可以完美的无缝融合。
Grafana是一个用于可视化大型测量数据的开源系统,它的功能非常强大,界面也非常漂亮,使用它可以创建自定义的控制面板,你可以在面板中配置要显示的数据和显示方式,它支持很多不同的数据源,比如:Graphite、InfluxDB、OpenTSDB、Elasticsearch、Prometheus等,而且它也支持众多的插件。
下面我们就体验下使用Grafana来展示Prometheus的指标数据。首先我们来安装Grafana,我们使用最简单的Docker安装方式:
$ docker run -d -p 3000:3000 grafana/grafana
运行上面的docker命令,Grafana就安装好了!你也可以采用其他的安装方式,参考官方的安装文档。安装完成之后,我们访问http://localhost:3000/进入Grafana的登陆页面,输入默认的用户名和密码(admin/admin)即可。

要使用Grafana,第一步当然是要配置数据源,告诉Grafana从哪里取数据,我们点击Add data source进入数据源的配置页面:

我们在这里依次填上:
  • Name: prometheus

  • Type: Prometheus

  • URL: http://localhost:9090

  • Access: Browser

要注意的是,这里的Access指的是Grafana访问数据源的方式,有Browser和Proxy两种方式。Browser方式表示当用户访问Grafana面板时,浏览器直接通过URL访问数据源的;而Proxy方式表示浏览器先访问Grafana的某个代理接口(接口地址是/api/datasources/proxy/),由Grafana的服务端来访问数据源的URL,如果数据源是部署在内网,用户通过浏览器无法直接访问时,这种方式非常有用。
配置好数据源,Grafana会默认提供几个已经配置好的面板供你使用,如下图所示,默认提供了三个面板:Prometheus Stats、Prometheus 2.0 Stats和Grafana metrics。点击Import就可以导入并使用该面板。

我们导入Prometheus 2.0 Stats这个面板,可以看到下面这样的监控面板。如果你的公司有条件,可以申请个大显示器挂在墙上,将这个面板投影在大屏上,实时观察线上系统的状态,可以说是非常cool 的。

五、使用Exporter收集指标

目前为止,我们看到的都还只是一些没有实际用途的指标,如果我们要在我们的生产环境真正使用Prometheus,往往需要关注各种各样的指标,譬如服务器的CPU负载、内存占用量、IO开销、入网和出网流量等等。正如上面所说,Prometheus是使用Pull的方式来获取指标数据的,要让Prometheus从目标处获得数据,首先必须在目标上安装指标收集的程序,并暴露出HTTP接口供Prometheus查询,这个指标收集程序被称为Exporter,不同的指标需要不同的Exporter来收集,目前已经有大量的Exporter可供使用,几乎囊括了我们常用的各种系统和软件,官网列出了一份 常用Exporter的清单,各个Exporter都遵循一份端口约定,避免端口冲突,即从9100开始依次递增,这里是完整的Exporter端口列表。另外值得注意的是,有些软件和系统无需安装Exporter,这是因为他们本身就提供了暴露Prometheus格式的指标数据的功能,比如Kubernetes、Grafana、Etcd、Ceph等。
这一节就让我们来收集一些有用的数据。

5.1 收集服务器指标

首先我们来收集服务器的指标,这需要安装node_exporter,这个exporter用于收集*NIX内核的系统,如果你的服务器是Windows,可以使用WMI exporter。
和Prometheus server一样,node_exporter也是开箱即用的:
$ wget https://github.com/prometheus/node_exporter/releases/download/v0.16.0/node_exporter-0.16.0.linux-amd64.tar.gz$ tar xvfz node_exporter-0.16.0.linux-amd64.tar.gz$ cd node_exporter-0.16.0.linux-amd64$ ./node_exporter
node_exporter启动之后,我们访问下/metrics接口看看是否能正常获取服务器指标:
$ curl http://localhost:9100/metrics
如果一切OK,我们可以修改Prometheus的配置文件,将服务器加到scrape_configs中:
scrape_configs:  - job_name: 'prometheus'    static_configs:      - targets: ['192.168.0.107:9090']  - job_name: 'server'    static_configs:      - targets: ['192.168.0.107:9100']
修改配置后,需要重启Prometheus服务,或者发送HUP信号也可以让Prometheus重新加载配置:
$ killall -HUP prometheus
在Prometheus Web UI的Status -> Targets中,可以看到新加的服务器:

在Graph页面的指标下拉框可以看到很多名称以node开头的指标,譬如我们输入node_load1观察服务器负载:

如果想在Grafana中查看服务器的指标,可以在Grafana的Dashboards页面搜索node exporter,有很多的面板模板可以直接使用,譬如:Node Exporter Server Metrics或者Node Exporter Full等。我们打开Grafana 的Import dashboard页面,输入面板的URL(https://grafana.com/dashboards/405)或者 ID(405)即可。

注意事项

一般情况下,node_exporter都是直接运行在要收集指标的服务器上的,官方不推荐用Docker来运行node_exporter。如果逼不得已一定要运行在Docker里,要特别注意,这是因为Docker的文件系统和网络都有自己的namespace,收集的数据并不是宿主机真实的指标。可以使用一些变通的方法,比如运行Docker时加上下面这样的参数:
docker run -d \  --net="host" \  --pid="host" \  -v "/:/host:ro,rslave" \  quay.io/prometheus/node-exporter \  --path.rootfs /host
关于node_exporter的更多信息,可以参考node_exporter的文档和Prometheus的官方指南Monitoring Linux host metrics with the Node Exporter,另外,Julius Volz的这篇文章How To Install Prometheus using Docker on Ubuntu 14.04也是很好的入门材料。

5.2 收集MySQL指标

mysqld_exporter是Prometheus官方提供的一个exporter,我们首先 下载最新版本 并解压(开箱即用):
$ wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.11.0/mysqld_exporter-0.11.0.linux-amd64.tar.gz$ tar xvfz mysqld_exporter-0.11.0.linux-amd64.tar.gz$ cd mysqld_exporter-0.11.0.linux-amd64/
mysqld_exporter需要连接到mysqld才能收集它的指标,可以通过两种方式来设置mysqld数据源。第一种是通过环境变量DATA_SOURCE_NAME,这被称为DSN(数据源名称),它必须符合DSN的格式,一个典型的DSN格式像这样:user:password@(host:port)/
$ export DATA_SOURCE_NAME='root:123456@(192.168.0.107:3306)/'$ ./mysqld_exporter另一种方式是通过配置文
另一种方式是通过配置文件,默认的配置文件是~/.my.cnf,或者通过--config.my-cnf 参数指定:
$ ./mysqld_exporter --config.my-cnf=".my.cnf"
配置文件的格式如下:
$ cat .my.cnf[client]host=localhostport=3306user=rootpassword=123456
如果要把MySQL的指标导入Grafana,可以参考这些Dashboard JSON。(https://github.com/percona/grafana-dashboards)

注意事项

这里为简单起见,在mysqld_exporter中直接使用了root连接数据库,在真实环境中,可以为mysqld_exporter创建一个单独的用户,并赋予它受限的权限(PROCESS、REPLICATION CLIENT、SELECT),最好还限制它的最大连接数(MAX_USER_CONNECTIONS)。
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'password' WITH MAX_USER_CONNECTIONS 3;GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';

5.3 收集Nginx指标

官方提供了两种收集Nginx指标的方式。第一种是Nginx metric library,这是一段Lua脚本(prometheus.lua),Nginx需要开启Lua支持(libnginx-mod-http-lua模块)。为方便起见,也可以使用OpenResty的 OPM(OpenResty Package Manager) 或者luarocks(The Lua package manager)来安装。第二种是Nginx VTS exporter,这种方式比第一种要强大的多,安装要更简单,支持的指标也更丰富,它依赖于nginx-module-vts 模块,vts模块可以提供大量的Nginx指标数据,可以通过JSON、HTML等形式查看这些指标。Nginx VTS exporter就是通过抓取/status/format/json接口来将vts的数据格式转换为Prometheus的格式。不过,在nginx-module-vts最新的版本中增加了一个新接口:/status/format/prometheus,这个接口可以直接返回Prometheus的格式,从这点这也能看出Prometheus的影响力,估计Nginx VTS exporter很快就要退役了(TODO:待验证)。
除此之外,还有很多其他的方式来收集Nginx的指标,比如:nginx_exporter 通过抓取Nginx自带的统计页面/nginx_status可以获取一些比较简单的指标(需要开启ngx_http_stub_status_module模块);nginx_request_exporter通过syslog协议收集并分析Nginx的access log来统计HTTP请求相关的一些指标;nginx-prometheus-shiny-exporter和nginx_request_exporter类似,也是使用syslog协议来收集access log,不过它是使用Crystal语言写的。还有vovolie/lua-nginx-prometheus基于Openresty、Prometheus、Consul、Grafana实现了针对域名和Endpoint级别的流量统计。
有需要或感兴趣的同学可以对照说明文档自己安装体验下,这里就不一一尝试了。

5.4 收集JMX指标

最后让我们来看下如何收集Java应用的指标,Java应用的指标一般是通过JMX(Java Management Extensions)来获取的,顾名思义,JMX是管理Java的一种扩展,它可以方便的管理和监控正在运行的Java程序。
JMX Exporter用于收集JMX指标,很多使用Java的系统,都可以使用它来收集指标,比如:Kafaka、Cassandra等。首先我们下载JMX Exporter:
$ wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.3.1/jmx_prometheus_javaagent-0.3.1.jar
JMX Exporter是一个Java Agent程序,在运行Java程序时通过-javaagent参数来加载:
$ java -javaagent:jmx_prometheus_javaagent-0.3.1.jar=9404:config.yml -jar spring-boot-sample-1.0-SNAPSHOT.jar
其中,9404是JMX Exporter暴露指标的端口,config.yml是JMX Exporter的配置文件,它的内容可以参考JMX Exporter的配置说明 。然后检查下指标数据是否正确获取:
$ curl http://localhost:9404/metrics

六、告警和通知

至此,我们能收集大量的指标数据,也能通过强大而美观的面板展示出来。不过作为一个监控系统,最重要的功能,还是应该能及时发现系统问题,并及时通知给系统负责人,这就是Alerting(告警)。Prometheus的告警功能被分成两部分:一个是告警规则的配置和检测,并将告警发送给Alertmanager,另一个是Alertmanager,它负责管理这些告警,去除重复数据,分组,并路由到对应的接收方式,发出报警。常见的接收方式有:Email、PagerDuty、HipChat、Slack、OpsGenie、WebHook 等。

6.1 配置告警规则

我们在上面介绍Prometheus的配置文件时了解到,它的默认配置文件prometheus.yml有四大块:global、alerting、rule_files、scrape_config,其中rule_files块就是告警规则的配置项,alerting块用于配置Alertmanager,这个我们下一节再看。现在,先让我们在rule_files块中添加一个告警规则文件:
rule_files:  - "alert.rules"
然后参考官方文档,创建一个告警规则文件 alert.rules
groups:- name: examplerules:  # Alert for any instance that is unreachable for >5 minutes.- alert: InstanceDownexpr: up == 0for: 5mlabels:severity: pageannotations:summary: "Instance {{ $labels.instance }} down"description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."  # Alert for any instance that has a median request latency >1s.- alert: APIHighRequestLatencyexpr: api_http_request_latencies_second{quantile="0.5"} > 1for: 10mannotations:summary: "High request latency on {{ $labels.instance }}"description: "{{ $labels.instance }} has a median request latency above 1s (current value: {{ $value }}s)"
这个规则文件里,包含了两条告警规则:InstanceDownAPIHighRequestLatency。顾名思义,InstanceDown表示当实例宕机时(up === 0)触发告警,APIHighRequestLatency表示有一半的API请求延迟大于1s时(api_http_request_latencies_second{quantile="0.5"} > 1)触发告警。配置好后,需要重启下Prometheus server,然后访问http://localhost:9090/rules可以看到刚刚配置的规则:

访问http://localhost:9090/alerts可以看到根据配置的规则生成的告警:

这里我们将一个实例停掉,可以看到有一条alert的状态是PENDING,这表示已经触发了告警规则,但还没有达到告警条件。这是因为这里配置的for参数是5m,也就是5分钟后才会触发告警,我们等5分钟,可以看到这条alert的状态变成了FIRING

6.2 使用Alertmanager发送告警通知

虽然Prometheus的/alerts页面可以看到所有的告警,但是还差最后一步:触发告警时自动发送通知。这是由Alertmanager来完成的,我们首先 下载并安装Alertmanager,和其他Prometheus的组件一样,Alertmanager也是开箱即用的:
$ wget https://github.com/prometheus/alertmanager/releases/download/v0.15.2/alertmanager-0.15.2.linux-amd64.tar.gz$ tar xvfz alertmanager-0.15.2.linux-amd64.tar.gz$ cd alertmanager-0.15.2.linux-amd64$ ./alertmanager
Alertmanager启动后默认可以通过http://localhost:9093/来访问,但是现在还看不到告警,因为我们还没有把Alertmanager配置到Prometheus中,我们回到Prometheus的配置文件prometheus.yml,添加下面几行:
alerting:alertmanagers:- scheme: httpstatic_configs:- targets:- "192.168.0.107:9093"
这个配置告诉Prometheus,当发生告警时,将告警信息发送到Alertmanager,Alertmanager的地址为http://192.168.0.107:9093。也可以使用命名行的方式指定Alertmanager:
$ ./prometheus -alertmanager.url=http://192.168.0.107:9093
这个时候再访问Alertmanager,可以看到Alertmanager已经接收到告警了:

下面的问题就是如何让Alertmanager将告警信息发送给我们了,我们打开默认的配置文件alertmanager.ym
global:resolve_timeout: 5m
route:group_by: ['alertname']group_wait: 10sgroup_interval: 10srepeat_interval: 1hreceiver: 'web.hook'receivers:- name: 'web.hook'webhook_configs:- url: 'http://127.0.0.1:5001/'inhibit_rules:- source_match:severity: 'critical'target_match:severity: 'warning'equal: ['alertname', 'dev', 'instance']
参考官方的配置手册了解各个配置项的功能,其中global块表示一些全局配置;route块表示通知路由,可以根据不同的标签将告警通知发送给不同的 receiver,这里没有配置routes项,表示所有的告警都发送给下面定义的web.hook这个receiver;如果要配置多个路由,可以参考这个例子:
routes:- receiver: 'database-pager'group_wait: 10smatch_re:service: mysql|cassandra
- receiver: 'frontend-pager'group_by: [product, environment]match:team: frontend
紧接着,receivers 块表示告警通知的接收方式,每个receiver包含一个name和一个xxx_configs,不同的配置代表了不同的接收方式,Alertmanager内置了下面这些接收方式:
  • email_config

  • hipchat_config

  • pagerduty_config

  • pushover_config

  • slack_config

  • opsgenie_config

  • victorops_config

  • wechat_configs

  • webhook_config

虽然接收方式很丰富,但是在国内,其中大多数接收方式都很少使用。最常用到的,莫属email_config和webhook_config,另外wechat_configs可以支持使用微信来告警,也是相当符合国情的了。
其实告警的通知方式是很难做到面面俱到的,因为消息软件各种各样,每个国家还可能不同,不可能完全覆盖到,所以Alertmanager已经决定不再添加新的receiver了,而是推荐使用webhook来集成自定义的接收方式。可以参考 这些集成的例子,譬如将钉钉接入Prometheus AlertManager WebHook。
(http://theo.im/blog/2017/10/16/release-prometheus-alertmanager-webhook-for-dingtalk/)

七、学习更多

到这里,我们已经学习了Prometheus的大多数功能,结合Prometheus + Grafana + Alertmanager完全可以搭建一套非常完整的监控系统。不过在真正使用时,我们会发现更多的问题。

7.1 服务发现

由于Prometheus是通过Pull的方式主动获取监控数据,所以需要手工指定监控节点的列表,当监控的节点增多之后,每次增加节点都需要更改配置文件,非常麻烦,这个时候就需要通过服务发现(service discovery,SD)机制去解决。Prometheus支持多种服务发现机制,可以自动获取要收集的targets,可以参考这里,包含的服务发现机制包括:azure、consul、dns、ec2、openstack、file、gce、kubernetes、marathon、triton、zookeeper(nerve、serverset),配置方法可以参考手册的Configuration页面。可以说SD机制是非常丰富的,但目前由于开发资源有限,已经不再开发新的SD机制,只对基于文件的SD机制进行维护。
关于服务发现网上有很多教程,譬如Prometheus官方博客中这篇文章Advanced Service Discovery in Prometheus 0.14.0对此有一个比较系统的介绍,全面的讲解了relabeling配置,以及如何使用DNS-SRV、Consul 和文件来做服务发现。另外,官网还提供了一个基于文件的服务发现的入门例子,Julius Volz写的Prometheus workshop入门教程中也使用了DNS-SRV来当服务发现。

7.2 告警配置管理

无论是Prometheus的配置还是Alertmanager的配置,都没有提供API供我们动态的修改。一个很常见的场景是,我们需要基于Prometheus做一套可自定义规则的告警系统,用户可根据自己的需要在页面上创建修改或删除告警规则,或者是修改告警通知方式和联系人,正如在Prometheus Google Groups里的这个用户的问题:How to dynamically add alerts rules in rules.conf and prometheus yml file via API or something?不过遗憾的是,Simon Pasquier在下面说到,目前并没有这样的API,而且以后也没有这样的计划来开发这样的API,因为这样的功能更应该交给譬如Puppet、Chef、Ansible、Salt这样的配置管理系统。

7.3 使用Pushgateway

Pushgateway主要用于收集一些短期的jobs,由于这类jobs存在时间较短,可能在Prometheus来Pull之前就消失了。官方对什么时候该使用Pushgateway有一个很好的说明。

总结

这篇博客参考了网络上大量关于Prometheus的中文资料,有文档,也有博客,比如1046102779的Prometheus非官方中文手册,宋佳洋的电子书《Prometheus实战》,在这里对这些原作者表示敬意。在Prometheus官方文档的Media页面,也提供了很多学习资源。
关于Prometheus,还有非常重要的一部分内容这篇博客没有涉及到,正如博客一开头所讲的,Prometheus是继Kubernetes之后第二个加入CNCF的项目,Prometheus和Docker、Kubernetes的结合非常紧密,使用Prometheus作为Docker和Kubernetes的监控系统也越来越主流。关于Docker的监控,可以参考官网的一篇指南:Monitoring Docker container metrics using cAdvisor,它介绍了如何使用cAdvisor来对容器进行监控;不过Docker现在也开始原生支持Prometheus的监控了,参考Docker的官方文档Collect Docker metrics with Prometheus;关于Kubernetes的监控,Kubernetes中文社区 里有不少关于Promehtheus 的资源,另外,《如何以优雅的姿势监控Kubernetes》这本电子书也对Kubernetes的监控有一个比较全面的介绍。
最近两年Prometheus的发展非常迅速,社区也非常活跃,国内研究Prometheus的人也越来越多。随着微服务,DevOps,云计算,云原生等概念的普及,越来越多的企业开始使用Docker和Kubernetes来构建自己的系统和应用,像Nagios和Cacti这样的老牌监控系统会变得越来越不适用,相信Prometheus最终会发展成一个最适合云环境的监控系统。

附录:什么是时序数据库?

上文提到Prometheus是一款基于时序数据库的监控系统,时序数据库常简写为TSDB(Time Series Database)。很多流行的监控系统都在使用时序数据库来保存数据,这是因为时序数据库的特点和监控系统不谋而合。
  • 增:需要频繁的进行写操作,而且是按时间排序顺序写入

  • 删:不需要随机删除,一般情况下会直接删除一个时间区块的所有数据

  • 改:不需要对写入的数据进行更新

  • 查:需要支持高并发的读操作,读操作是按时间顺序升序或降序读,数据量非常大,缓存不起作用

DB-Engines上有一个关于时序数据库的排名,下面是排名靠前的几个(2018年10月):
  • InfluxDB:https://influxdata.com/
  • Kdb+:http://kx.com/
  • Graphite:http://graphiteapp.org/
  • RRDtool:http://oss.oetiker.ch/rrdtool/
  • OpenTSDB:http://opentsdb.net/
  • Prometheus:https://prometheus.io/
  • Druid:http://druid.io/



数据湖存储架构选型

尝鲜!Flink1.12.2+Hudi0.9.0集成开发

实操 | Flink1.12.1通过Table API / Flink SQL读取HBase2.4.0

数据湖架构、战略和分析的8大错误认知
浏览 46
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报