JVM 默认会通过 JMX 的收藏识使方式暴露基础指标 ,很多中间件也会通过 JMX 的备用方式暴露业务指标,比如 Kafka 、小知Zookeeper 、监控ActiveMQ 、收藏识使Cassandra 、备用Spark 、小知Tomcat、监控Flink 等等。收藏识使掌握了 JMX 监控方式,备用就掌握了一批程序的小知监控方式 。本节介绍 JMX-Exporter 的监控使用,利用 JMX-Exporter 把 JMX 监控数据暴露为 Prometheus 可识别的免费模板收藏识使格式。
JMX(Java Management Extensions)是备用 Java 管理扩展的简称,是小知一种为 Java 应用程序植入管理功能的框架 。Java 类程序经常使用 JMX 暴露监控指标数据,也可以通过 JMX 来控制 Java 类程序,典型的比如通过 JMX 触发程序 GC 。
Java 程序里,某个类如果实现了 MBean 接口 ,那么这个类就可以通过 JMX 来读取和修改这个类的属性,也可以调用这个类的源码库方法 。JMX 通过 MBeanServer 来管理 MBean,MBeanServer 是一个管理器,它可以管理多个 MBean,每个 MBean 都有一个 ObjectName,用来唯一标识这个 MBean。
更新信息可以参考 JMX Specification。非本文重点。
JMX-Exporter 是 Prometheus 社区提供的一个工具 ,用来把 JMX 暴露的监控指标数据转换为 Prometheus 可识别的格式 。JMX-Exporter 通过 HTTP 服务的香港云服务器方式暴露监控指标数据,Prometheus 通过 HTTP 协议来拉取监控指标数据 。
JMX-Exporter 就是个 jar 包 ,以 javaagent(何为 javaagent,需要读者自行 Google) 的方式运行,和业务 Java(或 Scala) 程序运行在一个 JVM 虚拟机里。有了 JMX-Exporter ,业务程序无需暴露 JMX 端口了,JMX-Exporter 会把 JMX 暴露的监控指标数据转换为 Prometheus 可识别的格式 ,然后通过 HTTP 只读方式暴露出去 ,也更为安全 。
因为 JMX-Exporter 是高防服务器个 jar 包 ,所以安装非常简单,只需要把 jar 包下载到服务器上就可以了 。JMX-Exporter 的下载地址是 https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/ ,下载最新版本的 jar 包即可。
比如我们把下载的 jar 包放在 /opt/jmx-exporter 目录,另外,建立 /etc/jmx-exporter 目录放置 JMX-Exporter 所需配置文件 。像 Kafka,暴露的 JMX 指标非常非常多 ,我们不需要全部采集,亿华云只需要采集我们关心的指标即可 。所以,我们需要配置文件来告诉 JMX-Exporter,我们需要采集哪些指标。
JMX-Exporter 提供了很多样例配置 ,地址在这里 :https://github.com/prometheus/jmx_exporter/tree/main/example_configs 。
实际上 ,新版 Zookeeper 已经直接暴露了 Prometheus 协议的监控数据 ,无需通过 JMX 方式采集了。另外,Zookeeper 还提供了四字命令的监控数据采集方式 ,比如 Categraf 的 input.zookeeper 插件就是云计算采用的这种方式 。
不过,本文主要是演示 JMX 的方式 ,所以还是使用 JMX 的方式来采集 Zookeeper 的监控数据 。
首先,从 https://github.com/prometheus/jmx_exporter/tree/main/example_configs 这里找到 Zookeeper 的配置样例文件,下载到 /etc/jmx-exporter/zookeeper.yml。然后把 jmx-exporter 的 jar 包作为 javaagent 启动参数加入 Zookeeper 的启动命令即可 。
复制# zookeeper-env.sh SERVER_JVMFLAGS="-javaagent:/opt/jmx-exporter/jmx-exporter.jar=7070:/etc/jmx-exporter/zookeeper.yml"1.2.Zookeeper 有个 zookeeper-env.sh 控制 Zookeeper 的启动参数,我们在这里加入 javaagent 启动参数,然后重启 Zookeeper 即可。上例是把 JMX-Exporter 的 HTTP 服务端口设置为 7070 ,可以根据实际情况修改,配置文件指定为 /etc/jmx-exporter/zookeeper.yml。
OK ,现在可以测试了,先看 7070 端口是否在监听 ,如果在监听,就可以请求这个端口的 /metrics 接口采集 Prometheus 协议的监控数据了。
复制$ netstat -tlnp | grep 7070 tcp 0 0 0.0.0.0:7070 0.0.0.0:* LISTEN 892/java $ curl -s localhost:7070/metrics | head # HELP jvm_threads_current Current thread count of a JVM # TYPE jvm_threads_current gauge jvm_threads_current 16.0 # HELP jvm_threads_daemon Daemon thread count of a JVM # TYPE jvm_threads_daemon gauge jvm_threads_daemon 12.0 # HELP jvm_threads_peak Peak thread count of a JVM # TYPE jvm_threads_peak gauge jvm_threads_peak 16.0 # HELP jvm_threads_started_total Started thread count of a JVM1.2.3.4.5.6.7.8.9.10.11.12.13.14.可以看到,Zookeeper 的监控数据已经暴露出来了,接下来就可以采集这些数据了,抓取 Prometheus 协议的监控数据有很多方式 ,可以直接使用 Prometheus 自身来抓取,也可以通过 Categraf 的 input.prometheus 插件来抓取,也可以通过 vmagent 来抓取 ,大家自行决策即可。
从 JMX-Exporter 提供的样例配置目录,下载 kafka.yml ,然后导出 KAFKA_OPTS 环境变量即可 。
复制$ export KAFKA_OPTS=-javaagent:/opt/jmx-exporter/jmx-exporter.jar=7071:/etc/jmx-exporter/kafka.yml $ /opt/kafka_2.11-0.10.1.0/bin/kafka-server-start.sh /opt/kafka_2.11-0.10.1.0/conf/server.properties1.2.上例中,我们把端口换成了7071 ,配置文件指定为 /etc/jmx-exporter/kafka.yml 。测试一下端口是否成功监听 :
复制$ netstap -tlnp | grep 7071 tcp6 0 0 :::7071 :::* LISTEN 19288/java $ curl -s localhost:7071 | grep -i kafka | head # HELP kafka_server_replicafetchermanager_minfetchrate Attribute exposed for management (kafka.server<type=ReplicaFetcherManager, name=MinFetchRate, clientId=Replica><>Value) # TYPE kafka_server_replicafetchermanager_minfetchrate untyped kafka_server_replicafetchermanager_minfetchrate{ clientId="Replica",} 0.0 # HELP kafka_network_requestmetrics_totaltimems Attribute exposed for management (kafka.network<type=RequestMetrics, name=TotalTimeMs, request=OffsetFetch><>Count) # TYPE kafka_network_requestmetrics_totaltimems untyped kafka_network_requestmetrics_totaltimems{ request="OffsetFetch",} 0.0 kafka_network_requestmetrics_totaltimems{ request="JoinGroup",} 0.0 kafka_network_requestmetrics_totaltimems{ request="DescribeGroups",} 0.0 kafka_network_requestmetrics_totaltimems{ request="LeaveGroup",} 0.0 kafka_network_requestmetrics_totaltimems{ request="GroupCoordinator",} 0.01.2.3.4.5.6.7.8.9.10.11.12.13.14.一切正常哈 ,如果你的 Kafka 是通过 systemd 运行的,可以类似下面的方式来配置 kafka.service 文件 :
复制... [Service] Restart=on-failure Environment=KAFKA_OPTS=-javaagent:/opt/jmx-exporter/jmx-exporter.jar=7071:/etc/jmx-exporter/kafka.yml ExecStart=/opt/kafka/bin/kafka-server-start.sh /etc/kafka/server.properties ExecStop=/opt/kafka/bin/kafka-server-stop.sh TimeoutStopSec=600 User=kafka ...1.2.3.4.5.6.7.8.9.使用 jmx-exporter jar 包的时候 ,会引用一个配置文件 ,不同的 Java 应用可能会通过 jmx 的方式暴露特别多的监控指标,显然,我们不需要采集所有 ,具体要采集哪些指标,就是靠 jmx-exporter jar 包引用的那个配置文件决定的。我们来看一下 /etc/jmx-exporter/zookeeper.yml 的内容:
复制rules: # replicated Zookeeper - pattern: "org.apache.ZooKeeperService<name0=ReplicatedServer_id(\\d+)><>(\\w+)" name: "zookeeper_$2" type: GAUGE - pattern: "org.apache.ZooKeeperService<name0=ReplicatedServer_id(\\d+), name1=replica.(\\d+)><>(\\w+)" name: "zookeeper_$3" type: GAUGE labels: replicaId: "$2" - pattern: "org.apache.ZooKeeperService<name0=ReplicatedServer_id(\\d+), name1=replica.(\\d+), name2=(\\w+)><>(Packets\\w+)" name: "zookeeper_$4" type: COUNTER labels: replicaId: "$2" memberType: "$3" - pattern: "org.apache.ZooKeeperService<name0=ReplicatedServer_id(\\d+), name1=replica.(\\d+), name2=(\\w+)><>(\\w+)" name: "zookeeper_$4" type: GAUGE labels: replicaId: "$2" memberType: "$3" - pattern: "org.apache.ZooKeeperService<name0=ReplicatedServer_id(\\d+), name1=replica.(\\d+), name2=(\\w+), name3=(\\w+)><>(\\w+)" name: "zookeeper_$4_$5" type: GAUGE labels: replicaId: "$2" memberType: "$3" # standalone Zookeeper - pattern: "org.apache.ZooKeeperService<name0=StandaloneServer_port(\\d+)><>(\\w+)" type: GAUGE name: "zookeeper_$2" - pattern: "org.apache.ZooKeeperService<name0=StandaloneServer_port(\\d+), name1=InMemoryDataTree><>(\\w+)" type: GAUGE name: "zookeeper_$2"1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.这个配置文件里定义了一堆 rules,每个 rule 由四部分组成:pattern、name 、type、labels ,其中 pattern 是一个正则表达式 ,用来匹配 MBean 的 object name(什么是 MBean,什么是 object name 可以自行 Google,这里暂不展开),如果匹配到了就采集对应的 MBean 的数据 ,否则就不采集 。type 是指定了数据类型,labels 是指定了标签,标签值是来自 pattern 中提取到的正则数据。
所以 ,jmx 监控数据采集的关键点,其实是这个 rules 的最佳实践,也就是说,对于某个 Java 应用,你具体要采集哪些指标,这是真经验,真正有价值的东西 。
文章主要翻译了 https://alex.dzyoba.com/blog/jmx-exporter/ 并加入了一些个人理解。enjoy…make a better world :)
顶: 48踩: 36457
评论专区