Prometheus 是一个开源监控系统,它前身是 SoundCloud的告警工具包。从 2012 年开始,许多公司和组织开始使用 Prometheus。该项目的开发人员和用户社区很是活跃,愈来愈多的开发人员和用户参与到该项目中。目前它是一个独立的开源项目,且不依赖于任何公司。为了强调这点和明确该项目治理结构,Prometheus 在 2016 年继Kurberntes 以后,加入了 Cloud Native Computing Foundation。node
Prometheus 从根本上存储的全部数据都是时间序列数据(Time Serie Data,简称时序数据)。时序数据是具备时间戳的数据流,该数据流属于某个度量指标(Metric)和该度量指标下的多个标签(Label)。除了提供存储功能,Prometheus 还能够利用查询表达式来执行很是灵活和复杂的查询。linux
每一个时间序列(Time Serie,简称时序)由度量指标和一组标签键值对惟一肯定。ios
度量指标名称描述了被监控系统的某个测量特征(好比 http_requests_total 表示 http 请求总数)。度量指标名称由 ASCII 字母、数字、下划线和冒号组成,须匹配正则表达式 [a-zA-Z_:][a-zA-Z0-9_:]*
。git
标签开启了 Prometheus 的多维数据模型。对于同一个度量指标,不一样标签值组合会造成特定维度的时序。Prometheus 的查询语言能够经过度量指标和标签对时序数据进行过滤和聚合。改变任何度量指标上的任何标签值,都会造成新的时序。标签名称能够包含 ASCII 字母、数字和下划线,须匹配正则表达式 [a-zA-Z_][a-zA-Z0-9_]*
,带有 _ 下划线的标签名称保留为内部使用。标签值能够包含任意 Unicode 字符,包括中文。github
采样值(Sample)web
时序数据其实就是一系列采样值。每一个采样值包括:正则表达式
注解(Notation)docker
一个注解由一个度量指标和一组标签键值对构成。形式以下:shell
[metric name]{[label name]=[label value], ...}
复制代码
例如,度量指标为 api_http_requests_total,标签为 method="POST"、handler="/messages" 的注解表示以下:数据库
api_http_requests_total{method="POST", handler="/messages"} 复制代码
计数器是一种累计型的度量指标,它是一个只能递增的数值。计数器主要用于统计相似于服务请求数、任务完成数和错误出现次数这样的数据。
计量器表示一个既能够增长, 又能够减小的度量指标值。计量器主要用于测量相似于温度、内存使用量这样的瞬时数据。
直方图(Histogram)
直方图对观察结果(一般是请求持续时间或者响应大小这样的数据)进行采样,并在可配置的桶中对其进行统计。有如下几种方式来产生直方图(假设度量指标为 ):
<basename>_bucket{le="<upper inclusive bound>"}
<basename>_sum
<basename>_count
,也等同于把全部采样值放到一个桶里来计数 <basename>_bucket{le="+Inf"}
汇总(Summary)
相似于直方图,汇总也对观察结果进行采样。除了能够统计采样值总和和总数,它还可以按分位数统计。有如下几种方式来产生汇总(假设度量指标为 ):
<basename>{quantile="<φ>"}
<basename>_sum
<basename>_count
在 Prometheus 里,能够从中抓取采样值的端点称为实例,为了性能扩展而复制出来的多个这样的实例造成了一个任务。
例以下面的 api-server 任务有四个相同的实例:
job: api-server
instance 1: 1.2.3.4:5670
instance 2: 1.2.3.4:5671
instance 3: 5.6.7.8:5670
instance 4: 5.6.7.8:5671
复制代码
Prometheus 抓取完采样值后,会自动给采样值添加下面的标签和值:
另外每次抓取时,Prometheus 还会自动在如下时序里插入采样值:
up{job="[job-name]", instance="instance-id"}
:采样值为 1 表示实例健康,不然为不健康scrape_duration_seconds{job="[job-name]", instance="[instance-id]"}
:采样值为本次抓取消耗时间scrape_samples_post_metric_relabeling{job="<job-name>", instance="<instance-id>"}
:采样值为从新打标签后的采样值个数scrape_samples_scraped{job="<job-name>", instance="<instance-id>"}
:采样值为本次抓取到的采样值个数分组将相似性质的警报分类为单个通知。在许多系统一次性失败而且数百到数千个警报可能同时发生的较大中断期间,这尤为有用。
示例:发生网络分区时,群集中正在运行数十或数百个服务实例。一半的服务实例没法再访问数据库。Prometheus中的警报规则配置为在每一个服务实例没法与数据库通讯时发送警报。结果,数百个警报被发送到Alertmanager。
做为用户,人们只想得到单个页面,同时仍可以确切地看到哪些服务实例受到影响。所以,能够将Alertmanager配置为按群集和alertname对警报进行分组,以便发送单个紧凑通知。
经过配置文件中的路由树配置警报的分组,分组通知的定时以及这些通知的接收器。
若是某些其余警报已经触发,则抑制是抑制某些警报的通知的概念。示例:正在触发警报,通知没法访问整个集群。Alertmanager能够配置为在该特定警报触发时将与该集群有关的全部其余警报静音。这能够防止数百或数千个与实际问题无关的触发警报的通知。经过Alertmanager的配置文件配置禁止。
沉默是在给定时间内简单地静音警报的简单方法。基于匹配器配置静默,就像路由树同样。检查传入警报它们是否匹配活动静默的全部相等或正则表达式匹配器。若是他们这样作,则不会发送该警报的通知。在Alertmanager的Web界面中配置了静音。
Alertmanager对其客户的行为有特殊要求。这些仅适用于不使用Prometheus发送警报的高级用例。
Alertmanager支持配置以建立用于高可用性的集群。这可使用--cluster- *标志进行配置。重要的是不要在Prometheus和它的Alertmanagers之间加载平衡流量,而是将Prometheus指向全部Alertmanagers的列表。
cd /opt && wget https://github.com/prometheus/prometheus/releases/download/v2.12.0/prometheus-2.12.0.linux-amd64.tar.gz tar -zxf prometheus-2.12.0.linux-amd64.tar.gz mv prometheus-2.12.0.linux-amd64 prometheus chown root.root prometheus -R # 配置为服务 cat >/usr/lib/systemd/system/prometheus.service <<EOF [Unit] Description=Prometheus Documentation=https://prometheus.io/ After=network.target [Service] Type=simple ExecStart=/opt/prometheus/prometheus --config.file=/opt/prometheus/prometheus.yml Restart=on-failure [Install] WantedBy=multi-user.target EOF # 设置服务开机自启动 systemctl enable prometheus systemctl start prometheus # 直接启动 nohup ./prometheus --config.file=prometheus.yml 2>&1 1>prometheus.log & # 查看服务 [root@VM_0_13_centos pushgateway]# netstat -lntup |grep prometheus tcp6 0 0 :::9090 :::* LISTEN 16655/prometheus 复制代码
$ go get github.com/prometheus/prometheus/cmd/... $ prometheus --config.file=your_config.yml # 或者make build $ mkdir -p $GOPATH/src/github.com/prometheus $ cd $GOPATH/src/github.com/prometheus $ git clone https://github.com/prometheus/prometheus.git $ cd prometheus $ make build $ ./prometheus --config.file=your_config.yml 复制代码
docker run --name prometheus -d -p 127.0.0.1:9090:9090 prom/prometheus
复制代码
cd /opt && wget -c https://github.com/prometheus/alertmanager/releases/download/v0.18.0/alertmanager-0.18.0.linux-amd64.tar.gz tar zxf alertmanager-0.18.0.linux-amd64.tar.gz mv alertmanager-0.18.0.linux-amd64 alertmanager chown root.root alertmanager -R # 配置服务 cat >/usr/lib/systemd/system/alertmanager.service <<EOF [Unit] Description=Alertmanager Documentation=https://prometheus.io/ After=network.target [Service] Type=simple ExecStart=/opt/alertmanager/alertmanager --config.file=/opt/alertmanager/alertmanager.yml Restart=on-failure [Install] WantedBy=multi-user.target EOF # 设置服务开机自启动 systemctl enable alertmanager systemctl start alertmanager # 直接启动 nohup ./alertmanager --config.file=alertmanager.yml 2>&1 1>alertmanager.log & # 查看服务 [root@VM_0_13_centos pushgateway]# netstat -lntup |grep alertmanager tcp6 0 0 :::9094 :::* LISTEN 17237/alertmanager tcp6 0 0 :::9093 :::* LISTEN 17237/alertmanager udp6 0 0 :::9094 :::* 17237/alertmanager 复制代码
$ GO15VENDOREXPERIMENT=1 go get github.com/prometheus/alertmanager/cmd/... # cd $GOPATH/src/github.com/prometheus/alertmanager $ alertmanager --config.file=<your_file> # 手动源码构建 $ mkdir -p $GOPATH/src/github.com/prometheus $ cd $GOPATH/src/github.com/prometheus $ git clone https://github.com/prometheus/alertmanager.git $ cd alertmanager $ make build $ ./alertmanager --config.file=<your_file> # amtool构建 $ make build BINARIES=amtool 复制代码
docker pull quay.io/prometheus/alertmanager
复制代码
利用node_export来监控主机,官方也提供了不少其余的export能够用来直接使用
cd /opt && wget -c https://github.com/prometheus/node_exporter/releases/download/v0.18.1/node_exporter-0.18.1.linux-amd64.tar.gz tar zxf node_exporter-0.18.1.linux-amd64.tar.gz mv node_exporter-0.18.1.linux-amd64 node_exporter chown root.root node_exporter -R # 配置服务 cat >/usr/lib/systemd/system/node_exporter.service <<EOF [Unit] Description=node_exporter Documentation=https://prometheus.io/ After=network.target [Service] Type=simple ExecStart=/opt/node_exporter/node_exporter Restart=on-failure [Install] WantedBy=multi-user.target EOF # 设置服务开机自启动 systemctl enable node_exporter systemctl start node_exporter # 直接启动 nohup ./node_exporter --config.file=node_exporter.yml 2>&1 1>node_exporter.log & # 查看服务 [root@VM_0_13_centos pushgateway]# netstat -lntup |grep node_export tcp6 0 0 :::9100 :::* LISTEN 4551/node_exporter 复制代码
cd /opt && wget -c https://github.com/prometheus/pushgateway/releases/download/v0.9.1/pushgateway-0.9.1.linux-amd64.tar.gz tar zxf pushgateway-0.9.1.linux-amd64.tar.gz mv pushgateway-0.9.1.linux-amd64 pushgateway chown root.root pushgateway -R # 配置服务 cat >/usr/lib/systemd/system/pushgateway.service <<EOF [Unit] Description=pushgateway Documentation=https://prometheus.io/ After=network.target [Service] Type=simple ExecStart=/opt/pushgateway/pushgateway Restart=on-failure [Install] WantedBy=multi-user.target EOF # 设置服务开机自启动 systemctl enable pushgateway systemctl start pushgateway # 直接启动 nohup ./pushgateway --config.file=node_exporter.yml 2>&1 1>node_exporter.log & # 查看服务 [root@VM_0_13_centos pushgateway]# netstat -lntup |grep push tcp6 0 0 :::9091 :::* LISTEN 5982/pushgateway 复制代码
echo "some_metric 3.14" | curl --data-binary @- http://localhost:9091/metrics/job/some_job
复制代码
cat <<EOF | curl --data-binary @- http://localhost:9091/metrics/job/some_job/instance/some_instance # TYPE some_metric counter some_metric{label="val1"} 42 # TYPE another_metric gauge # HELP another_metric Just an example. another_metric 2398.283 EOF 复制代码
wget https://dl.grafana.com/oss/release/grafana-6.3.3-1.x86_64.rpm sudo yum localinstall grafana-6.3.3-1.x86_64.rpm -y systemctl enable grafana-server.service systemctl start grafana-server.service # web页面3000 登陆信息:admin/admin # 安装插件 grafana-cli plugins install grafana-piechart-panel systemctl restart grafana-server 复制代码
添加prometheus,填写prometheus的管理地址
经过https://grafana.com/grafana/dashboards中获取
# 修改/etc/grafana/grafana.ini [smtp] enabled = true host = smtp.163.com:465 user = 18329903316 # If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;""" password = xxxxxxxxxxxx ;cert_file = ;key_file = ;skip_verify = false from_address = 18329903316@163.com ;from_name = Grafana ;ehlo_identity = dashboard.example.com 复制代码
⚠️:Template variables are not supported in alert queries,在查询中不能使用模版语法,否则没法建立告警
告警测试
查看告警历史
告警触发
PromQL(Prometheus Query Language)是 Prometheus 本身开发的表达式语言,语言表现力很丰富,内置函数也不少。使用它能够对时序数据进行筛选和聚合。
PromQL 表达式计算出来的值有如下几种类型:
瞬时向量选择器
瞬时向量选择器用来选择一组时序在某个采样点的采样值。
最简单的状况就是指定一个度量指标,选择出全部属于该度量指标的时序的当前采样值。好比下面的表达式:
http_requests_total
复制代码
能够经过在后面添加用大括号包围起来的一组标签键值对来对时序进行过滤。好比下面的表达式筛选出了 job 为 prometheus,而且 group 为 canary 的时序:
http_requests_total{job="prometheus", group="canary"} 复制代码
匹配标签值时能够是等于,也可使用正则表达式。总共有下面几种匹配操做符:
下面的表达式筛选出了 environment 为 staging 或 testing 或 development,而且 method 不是 GET 的时序:
http_requests_total{environment=~"staging|testing|development",method!="GET"} 复制代码
度量指标名可使用内部标签 __name__
来匹配,表达式 http_requests_total
也能够写成 {__name__="http_requests_total"}
。表达式 {__name__=~"job:.*"}
匹配全部度量指标名称以 job:
打头的时序。
区间向量选择器
区间向量选择器相似于瞬时向量选择器,不一样的是它选择的是过去一段时间的采样值。能够经过在瞬时向量选择器后面添加包含在 []
里的时长来获得区间向量选择器。好比下面的表达式选出了全部度量指标为 http_requests_total 且 job 为 prometheus 的时序在过去 5 分钟的采样值。
http_requests_total{job="prometheus"}[5m] 复制代码
时长的单位能够是下面几种之一:
偏移修饰器
前面介绍的选择器默认都是以当前时间为基准时间,偏移修饰器用来调整基准时间,使其往前偏移一段时间。偏移修饰器紧跟在选择器后面,使用 offset
来指定要偏移的量。好比下面的表达式选择度量名称为 http_requests_total 的全部时序在 5 分钟前的采样值。
http_requests_total offset 5m
复制代码
下面的表达式选择 http_requests_total 度量指标在 1 周前的这个时间点过去 5 分钟的采样值。
http_requests_total[5m] offset 1w
复制代码
PromQL 的二元操做符支持基本的逻辑和算术运算,包含算术类、比较类和逻辑类三大类。
算术类二元操做符
算术类二元操做符有如下几种:
算术类二元操做符能够使用在标量与标量、向量与标量,以及向量与向量之间
二元操做符上下文里的向量特指瞬时向量,不包括区间向量。
比较类二元操做符
比较类二元操做符有如下几种:
比较类二元操做符一样能够使用在标量与标量、向量与标量,以及向量与向量之间。默认执行的是过滤,也就是保留值。能够经过在运算符后面跟 bool
修饰符来使得返回值 0 和 1,而不是过滤。
逻辑类二元操做符
逻辑操做符仅用于向量与向量之间。
具体运算规则以下:
vector1 and vector2
的结果由在 vector2 里有匹配(标签键值对组合相同)元素的 vector1 里的元素组成。vector1 or vector2
的结果由全部 vector1 里的元素加上在 vector1 里没有匹配(标签键值对组合相同)元素的 vector2 里的元素组成。vector1 unless vector2
的结果由在 vector2 里没有匹配(标签键值对组合相同)元素的 vector1 里的元素组成。二元操做符优先级
PromQL 的各种二元操做符运算优先级以下:
前面算术类和比较类操做符都须要在向量之间进行匹配。共有两种匹配类型,one-to-one
和 many-to-one
/ one-to-many
。
One-to-one 向量匹配
相同则为匹配,而且只会有一个匹配元素。可使用 ignoring
关键词来忽略不参与匹配的标签,或者使用 on
关键词来指定要参与匹配的标签。语法以下:
<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) <vector expr>
复制代码
好比对于下面的输入:
method_code:http_errors:rate5m{method="get", code="500"} 24 method_code:http_errors:rate5m{method="get", code="404"} 30 method_code:http_errors:rate5m{method="put", code="501"} 3 method_code:http_errors:rate5m{method="post", code="500"} 6 method_code:http_errors:rate5m{method="post", code="404"} 21 method:http_requests:rate5m{method="get"} 600 method:http_requests:rate5m{method="del"} 34 method:http_requests:rate5m{method="post"} 120 复制代码
执行下面的查询:
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m 复制代码
获得的结果为:
{method="get"} 0.04 // 24 / 600 {method="post"} 0.05 // 6 / 120 复制代码
也就是每一种 method 里 code 为 500 的请求数占总数的百分比。因为 method 为 put 和 del 的没有匹配元素因此没有出如今结果里。
Many-to-one / one-to-many 向量匹配
这种匹配模式下,某一边会有多个元素跟另外一边的元素匹配。这时就须要使用 group_left
或 group_right
组修饰符来指明哪边匹配元素较多,左边多则用 group_left,右边多则用 group_right。其语法以下:
<vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>
复制代码
组修饰符只适用于算术类和比较类操做符。
对于前面的输入,执行下面的查询:
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
复制代码
将获得下面的结果:
{method="get", code="500"} 0.04 // 24 / 600 {method="get", code="404"} 0.05 // 30 / 600 {method="post", code="500"} 0.05 // 6 / 120 {method="post", code="404"} 0.175 // 21 / 120 复制代码
也就是每种 method 的每种 code 错误次数占每种 method 请求数的比例。这里匹配的时候 ignoring 了 code,才使得两边能够造成 Many-to-one 形式的匹配。因为左边多,因此须要使用 group_left 来指明。
Many-to-one / one-to-many 过于高级和复杂,要尽可能避免使用。不少时候经过 ignoring 就能够解决问题。
PromQL 的聚合操做符用来将向量里的元素聚合得更少。总共有下面这些聚合操做符:
聚合操做符语法以下:
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
复制代码
其中 without
用来指定不须要保留的标签(也就是这些标签的多个值会被聚合),而 by
正好相反,用来指定须要保留的标签(也就是按这些标签来聚合)。
下面来看几个示例:
sum(http_requests_total) without (instance)
复制代码
http_requests_total 度量指标带有 application、instance 和 group 三个标签。上面的表达式会获得每一个 application 的每一个 group 在全部 instance 上的请求总数。效果等同于下面的表达式:
sum(http_requests_total) by (application, group)
复制代码
下面的表达式能够获得全部 application 的全部 group 的全部 instance 的请求总数。
sum(http_requests_total)
复制代码
Prometheus 内置了一些函数来辅助计算,下面介绍一些典型的,完整的列表请参考 官方文档。
将报警集成到睿象云
# 编辑prometheus.yml alerting: alertmanagers: - static_configs: - targets: - 'localhost:9093' rule_files: - "onealter.yml" 复制代码
# 编写onealter.yml groups: - name: test-rule rules: - alert: 节点内存使用量 expr: (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes+node_memory_Buffers_bytes+node_memory_Cached_bytes )) / node_memory_MemTotal_bytes * 100 > 40 for: 1m labels: user: prometheus annotations: summary: "{{$labels.instance}}:内存超过40%" description: "{{$labels.instance}}:内存超过40%" 复制代码
# 编辑 global: resolve_timeout: 5m route: group_by: ['alertname'] group_wait: 10s group_interval: 10s repeat_interval: 1h receiver: 'team-X-pager' receivers: - name: 'team-X-pager' webhook_configs: - url: 'http://api.aiops.com/alert/api/event/prometheus/f307ded7-9a96-4e34-101d-dfc421a8743a' send_resolved: true inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' equal: ['alertname', 'dev', 'instance'] 复制代码