概述
当你的 Java 应用运行起来之后,如果对其进行监控呢?Prometheus 社区开发了 JMX Exporter 来导出 JVM 的监控指标和自定义指标(自定义MBean),以便使用 Prometheus 来采集监控数据。本文将介绍如何利用 Prometheus 与 JMX Exporter 来监控你 Java 应用,并使用Grafana和Alertmanager对指标进行监控和告警。
动手之前,容我先简单介绍一下Prometheus和JmxExporter
Prometheus简介
Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB)。
Prometheus使用Go语言开发,是Google BorgMon监控系统的开源版本。2016年由Google发起Linux基金会旗下的原生云基金会(Cloud Native Computing Foundation)将Prometheus纳入其下第二大开源项目。Prometheus目前在开源社区相当活跃。Prometheus和Heapster(Heapster是K8S的一个子项目,用于获取集群的性能数据。)相比功能更完善、更全面。Prometheus性能也足够支撑上万台规模的集群。
系统架构图
从上图可以看出,Prometheus的主要模块包括:Prometheus server,Pushgateway,exporters,PromQL,Alertmanager以及图形界面。
- Prometheus Server 主要负责数据采集和存储,提供PromQL查询语言的支持。
- Alertmanager 警告管理器,用来进行报警。
- Push Gateway 支持临时性Job主动推送指标的中间网关。
- Exporters 输出被监控组件信息的HTTP接口。
- Grafana 监控数据展示Web UI。
基本原理
Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态,任意组件只要提供对应的HTTP接口就可以接入监控。不需要任何SDK或者其他的集成过程。这样做非常适合做虚拟化环境监控系统,比如VM、Docker、Kubernetes等。输出被监控组件信息的HTTP接口被叫做exporter 。目前互联网公司常用的组件大部分都有exporter可以直接使用,比如Varnish、Haproxy、Nginx、MySQL、Linux系统信息(包括磁盘、内存、CPU、网络等等)。其大概的工作流程是:
- Prometheus server 定期从配置好的 jobs 或者 exporters 中拉 metrics,或者接收来自Pushgateway 发过来的 metrics,或者从其他的 Prometheus server 中拉 metrics。
- Prometheus server 在本地存储收集到的 metrics,并运行已定义好的 alert.rules,记录新的时间序列或者向 Alertmanager 推送警报。
- Alertmanager 根据配置文件,对接收到的警报进行处理,发出告警。
- 在Grafana图形界面中,可视化查看采集数据。
JmxExporter介绍
什么是JmxExporter?
JMX Exporter 利用 Java 的 JMX 机制来读取 JVM 运行时的一些监控数据,然后将其转换为 Prometheus 所认知的 metrics 格式,以便让 Prometheus 对其进行监控采集。
如何使用JmxExporter暴露监控指标?
下面介绍如何通过 JMX Exporter 来暴露 Java 应用的 JVM 监控指标。JMX-Exporter 提供了两种用法:
- 启动独立进程。JVM 启动时指定参数,暴露 JMX 的 RMI 接口,JMX-Exporter 调用 RMI 获取 JVM 运行时状态数据,转换为 Prometheus metrics 格式,并暴露端口让 Prometheus 采集。
- JVM 进程内启动。JVM 启动时指定参数,通过 -javaagent 的形式运行 JMXExporter 的 jar 包,进程内读取 JVM 运行时状态数据,转换为 Prometheus metrics 格式,并暴露端口让 Prometheus 采集。
官方不推荐使用第一种方式,一方面配置复杂,另一方面因为它需要一个单独的进程,而这个进程本身的监控又成了新的问题,所以本文使用第二种用法暴露监控指标。
部署配置
Prometheus
本文使用docker的方式部署Prometheus,直接使用官方镜像运行。
提前在/Users/zero/Endless/ZhoujPractice/spring-boot-prometheus/config路径下创建Prometheus配置文件prometheus.yml和Prometheus规则文件prometheus_rules.yml,然后通过如下命令挂载到官方镜像中运行:
docker run \
-p 9090:9090 \
--name=prometheus \
-v /Users/zero/Endless/ZhoujPractice/spring-boot-prometheus/config:/etc/prometheus/ \
prom/prometheus
prometheus.yml配置文件
global:
scrape_interval: 10s
evaluation_interval: 10s
##告警组件配置
alerting:
alertmanagers:
- static_configs:
- targets: [ '192.168.164.xx:9093' ]
rule_files:
- "prometheus_rules.yml"
##数据采集Job配置
scrape_configs:
###以下内容为prometheus自身配置
- job_name: 'prometheus'
static_configs:
- targets: [ '192.168.164.xx:9090' ]
labels:
appname: 'prometheus'
###以下内容为SpringBoot应用配置
- job_name: 'springboot_prometheus'
scrape_interval: 5s
metrics_path: '/actuator/prometheus'
static_configs:
- targets: [ '192.168.164.xx:9999' ]
labels:
appname: 'springboot_prometheus'
###以下内容为jmx-exporter应用配置
- job_name: 'jmx-exporter'
scrape_interval: 10s
metrics_path: '/metrics'
static_configs:
- targets: [ '192.168.164.xx:8089' ]
labels:
appname: 'jmx-exporter'
prometheus_rules.yml配置文件
groups:
- name: InstanceDown #定义规则组
rules:
- alert: InstanceDown #定义报警名称
expr: up == 0 #Promql语句,触发规则
for: 1m # 一分钟
labels: #标签定义报警的级别和主机
name: instance
severity: Critical
annotations: #注解
summary: " {{ $labels.appname }}" #报警摘要,取报警信息的appname名称
description: " 服务停止运行 " #报警信息
value: "{{ $value }}%" # 当前报警状态值
- name: jmx-exporter-alert
rules:
- alert: jmx-exporter-qps
expr: zhouj_practice_springboot_prometheus_springboot_prometheus_bindcount > 10
for: 1m
labels:
severity: 'critical'
annotations:
summary: "instance: QPS > 10"
description: "instance: QPS > 10"
value: "{{ $value }}"
instance: "{{ $labels.instance }}"
容器运行起来之后,访问:http://localhost:9090/ 查看Prometheus部署是否成功!
能正常访问代表安装成功。顺便可以看一下配置的job和告警规则是否加载成功,分别如下图:
由于Java应用和JmxExporter还没有部署,所以对应Job状态为down。
Java应用
部署好Premetheus之后,接下来部署要监控的Java应用,本文直接使用Java -jar运行应用,JmxExporter以代理的模式运行。将Java应用的Jar包(spring-boot-prometheus-1.0-SNAPSHOT.jar)、JmxExporter的Jar(jmx_prometheus_javaagent-0.15.0.jar),还有JmxExporter配置文件jmx_exporter_config.yaml,放在相同目录下,执行如下命令:
java -javaagent:./jmx_prometheus_javaagent-0.15.0.jar=8089:jmx_exporter_config.yaml -jar -Dspring.jmx.enabled=true spring-boot-prometheus-1.0-SNAPSHOT.jar
说明:-Dspring.jmx.enabled=true 是因为我使用的spring的jmx注解,增加该参数进行MBean注册。
应用启动成功后,可以再去看一下Premetheus,此时可以看到所有的job都是UP状态。
选择一个Endpoint点击,可以看到抓取到的数据指标
到此,指标采集完成!接下来是指标的监控和指标的告警。
Grafana
虽然 Prometheus 提供的 Web UI 也可以很好的查看不同指标的视图,但是这个功能非常简单,只适合用来调试。要实现一个强大的监控系统,还需要一个能定制展示不同指标的面板,能支持不同类型的展现方式(曲线图、饼状图、热点图、TopN 等),这就是仪表盘(Dashboard)功能。
Grafana是一个用于可视化大型测量数据的开源系统,它的功能非常强大,界面也非常漂亮,使用它可以创建自定义的控制面板,你可以在面板中配置要显示的数据和显示方式,它支持很多不同的数据源,比如:Graphite、InfluxDB、OpenTSDB、Elasticsearch、Prometheus 等,而且它也支持众多的插件 。同样使用docker部署grafana,将宿主机grafana.ini配置文件挂在到容器内,执行以下命令:
docker run \
-d \
-p 3000:3000 \
--name=grafana \
-v /Users/zero/Endless/ZhoujPractice/spring-boot-prometheus/config/grafana.ini:/etc/grafana/grafana.ini \
grafana/grafana
说明:grafana.ini只是修改了Grafana邮件告警相关的配置,如果你不打算用Grafana告警,可以不用配置文件。
grafana.ini配置文件
#################################### SMTP / Emailing ##########################
[smtp]
enabled = true
host = smtp.163.com:465
user = xxx@163.com
# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;"""
password = 必须是授权码
;cert_file =
;key_file =
skip_verify = true
from_address = xxx@163.com
from_name = Grafana
# EHLO identity in SMTP dialog (defaults to instance_name)
;ehlo_identity = dashboard.example.com
# SMTP startTLS policy (defaults to 'OpportunisticStartTLS')
;startTLS_policy = NoStartTLS
[emails]
;welcome_email_on_sign_up = false
;templates_pattern = emails/*.html
运行后访问http://localhost:3000/login,user:admin pass:admin
添加Prometheus数据源
点击Add data source进入,选择Prometheus数据源
配置Prometheus地址,点击右下方保存测试按钮
出现如下提示,表示数据源配置成功
接下来是进行自定义指标配置,这里就不详细介绍,自定义指标如下:
这里添加三个指标,针对每个指标可以设置告警条件,首先需要配置告警渠道,选择你设置的渠道
配置完,点击Test可以测试渠道是否可以,如果成功会收到如下邮件
至此,Grafana的部署、配置和使用结束,Java应用的监控和告警功能算是完成(就是说后面的内容可以不用看)!但是在文章的开始,有介绍Prometheus的几个组件,为了保证文章的完成性,最后的AlertManager告警组件还是要介绍一下。
AlertManager
虽然Grafana是可以进行告警,但总觉得它不是专业干这事的,因此接下来介绍AlertManager组件的部署和配置,同样适用docker部署,执行如下命令:
docker run \
-d \
-p 9093:9093 \
--name alertmanager \
-v /Users/zero/Endless/ZhoujPractice/spring-boot-prometheus/config/alertmanager.yml:/etc/alertmanager/alertmanager.yml \
-v /Users/zero/Endless/ZhoujPractice/spring-boot-prometheus/config/default-monitor.tmpl:/etc/alertmanager/template/default-monitor.tmpl \
prom/alertmanager
挂载alertmanager.yml配置文件和default-monitor.tmpl模版配置文件。
alertmanager.yml配置文件
global:
resolve_timeout: 2m
smtp_smarthost: smtp.163.com:465
smtp_from: xxx@163.com
smtp_auth_username: xxx@163.com
smtp_auth_password: 必须是授权码
smtp_require_tls: false
##消息模板
templates:
- '/etc/alertmanager/template/*.tmpl'
route:
receiver: 'email' # 优先使用email发送
group_wait: 30s
group_interval: 60s
repeat_interval: 1h
group_by: [ cluster, alertname ]
# routes: #子路由,使用其他方式发送
# - receiver: other
# match_re:
# serverity: other
receivers:
- name: 'email'
email_configs:
- to: 'xxxx@getui.com'
send_resolved: true #告警恢复通知
html: '{{ template "email.html" . }}'
headers: { Subject: " {{ .CommonAnnotations.summary }}" }
default-monitor.tmpl模版配置文件
{{ define "email.html" }}
<table border="5">
<tr><td>alertname</td>
<td>instance</td>
<td>报警阀值</td>
<td>开始时间</td>
</tr>
{{ range $i, $alert := .Alerts }}
<tr><td>{{ index $alert.Labels "alertname" }}</td>
<td>{{ index $alert.Labels "instance" }}</td>
<td>{{ index $alert.Annotations "value" }}</td>
<td>{{ $alert.StartsAt }}</td>
</tr>
{{ end }}
</table>
{{ end }}
运行成功后,访问http://192.168.0.100/:9093,查看AlertManager运行状态
根据自己设置的告警条件,如果指标触发会收到相应的告警邮件。
感谢阅读!