集成 JMX 和 OpenTelemetry

Alex Boten 2025-10-14 10:16:36

JMX 是什么?

JMX 是 “Java Management Extensions” 的缩写,中文通常称为 “Java 管理扩展”。它是 Java 平台提供的一套标准框架,用于对 Java 应用程序、设备、系统资源进行监控和管理。

JMX 的核心作用包括:

  • 监控 Java 程序运行状态(如内存使用、线程数、类加载情况等);
  • 动态修改配置参数(无需重启应用);
  • 远程管理 Java 应用(通过 JConsole、VisualVM 等工具);
  • 集成到监控系统中,实现对 JVM 的集中监控。

很多 Java 应用(如 Kafka、Hadoop、Tomcat 等)都通过 JMX 暴露运行时指标,方便运维人员进行监控和故障排查。在监控领域,你就可以简单的理解 JMX 是一种 Java 应用暴露指标的标准方式。

很多新的开源项目直接暴露 Prometheus 协议的监控数据,确实更方便,但很多老的 Java 应用仍然通过 JMX 暴露指标数据,所以掌握 JMX 监控方式,等于掌握了一批 Java 应用的监控方式。

OpenTelemetry 的标准已经被业界普遍使用,JMX 也可以和 OpenTelemetry 集成。用于 JMX 的 OpenTelemetry 集成利用 YAML 中指定的配置文件来描述应用程序的指标应如何转换为 OpenTelemetry 指标。这些规则会提供给与 JMX API 交互的 JMX 指标抓取工具。许多现有的 Java 应用程序可配置为通过 JMX 发出指标。以下应用程序具有社区支持的预定义规则文件:

  • Activemq
  • Cassandra
  • Hbase
  • Hadoop
  • Jetty
  • Jvm
  • Kafka
  • Solr
  • Tomcat
  • Wildfly

这意味着,在使用 JMX 抓取工具时,可以将目标应用程序识别为上述选项之一,无需任何额外配置即可自动抓取指标。

使用 OpenTelemetry 的 JMX 集成从应用程序中提取数据有多种方法:

  • 运行 JMX 指标收集器 JAR 并将其指向您的应用程序
  • 将 OpenTelemetry Java 代理与应用程序一起运行
  • 运行 OpenTelemetry Collector 并配置 JMX 接收器以通过 JMX 获取指标

JMX 指标收集器是一种简单便捷的方法,可用于测试从 Java 应用程序导出指标,且所需的额外依赖最少。OpenTelemetry Java 代理是一种更成熟且经过验证的机制,但由于它引入了额外的 instrumentation,可能也会带来一些开销。如果在你的环境中运行单独的进程或工作负载是可接受的,那么 OpenTelemetry 收集器是一个可靠的替代方案。本文将探讨这三种选择。

配置

在深入了解 OpenTelemetry 集成之前,有必要确保将要测试的应用程序正确暴露 JMX 端点。以下命令在 Docker 容器中启动 Tomcat 服务器,以减少本地系统所需的依赖项数量。它使用 JAVA_OPTS 环境变量启用 JMX,并使其在 9999 端口上可用。

$ docker run -it --rm -p 9999:9999 -p 8888:8080 -e JAVA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.rmi.port=9999 -Djava.rmi.server.hostname=0.0.0.0 -Dcom.sun.management.jmxremote.ssl=false" tomcat:9.0

有许多工具可以验证 JMX 端口是否可访问以及是否在生成指标。以下使用 JConsole 并连接到已打开的端口:

$ jconsole localhost:9999

这将弹出一个应用程序,它可能会提示您连接不安全。在本地开发时,此警告可以安全地忽略。

JConsole

这些数据可通过远程 JMX 端口访问,我们已准备好与 OpenTelemetry 集成。

直接使用 JMX scraper

如前所述,JMX 抓取工具是最简便的入门方式。以下命令将:

  • 从 Maven 下载 JMX 抓取工具的最新发布版本
  • 运行 JMX 抓取工具,将其配置为从 Tomcat 收集遥测数据,并通过 JMX 收集指标,然后将这些指标输出到本地控制台。
$ wget https://repo1.maven.org/maven2/io/opentelemetry/contrib/opentelemetry-jmx-scraper/1.49.0-alpha/opentelemetry-jmx-scraper-1.49.0-alpha.jar

$ OTEL_METRICS_EXPORTER=console java -jar opentelemetry-jmx-scraper-1.49.0-alpha.jar -config - <<EOF
otel.jmx.service.url=service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi
otel.jmx.target.system=tomcat
EOF

该命令的输出让我们知道连接已建立,并且一些度量工具已创建:

WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::objectFieldOffset has been called by io.opentelemetry.internal.shaded.jctools.util.UnsafeAccess (file:/Users/alex/Downloads/opentelemetry-jmx-scraper-1.49.0-alpha.jar)
WARNING: Please consider reporting this to the maintainers of class io.opentelemetry.internal.shaded.jctools.util.UnsafeAccess
WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
2025-08-27 10:28:48 INFO metrics export interval (seconds) =  60
2025-08-27 10:28:48 WARNING SASL unsupported in current environment: class io.opentelemetry.contrib.jmxscraper.JmxConnectorBuilder cannot access class com.sun.security.sasl.Provider (in module java.security.sasl) because module java.security.sasl does not export com.sun.security.sasl to unnamed module @24313fcc
2025-08-27 10:28:48 INFO Connecting to service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi
2025-08-27 10:28:48 INFO tomcat: found 3 metric rules
2025-08-27 10:28:48 INFO JMX scraping started
2025-08-27 10:28:49 INFO Created Counter for tomcat.error.count
2025-08-27 10:28:49 INFO Created Counter for tomcat.request.count
2025-08-27 10:28:49 INFO Created Gauge for tomcat.request.duration.max
2025-08-27 10:28:49 INFO Created Counter for tomcat.request.duration.sum
2025-08-27 10:28:49 INFO Created Counter for tomcat.network.io
2025-08-27 10:28:49 INFO Created Counter for tomcat.network.io
2025-08-27 10:28:49 INFO Created UpDownCounter for tomcat.thread.count
2025-08-27 10:28:49 INFO Created UpDownCounter for tomcat.thread.limit
2025-08-27 10:28:49 INFO Created UpDownCounter for tomcat.thread.busy.count

使用JMX抓取工具是个不错的入门方法,但它确实需要一个额外的 JAR 包,如果我们已经在使用 Java 代理,可能就不希望这样了。

使用 OpenTelemetry Java 代理

除了提供 JMX 集成外,Java 代理还提供了自动检测应用程序的功能。出于这个原因,它比 JMX 抓取工具更常用。以下命令:

  • 下载最新发布版本的 OpenTelemetry Java agent jar
  • 通过将本地目录挂载到容器中,将 jar 包归档文件添加到 Docker 环境中
  • 使用一些额外的环境变量运行与之前相同的 Tomcat 应用程序,以加载 agent jar 包
$ wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.19.0/opentelemetry-javaagent.jar

$ docker run -it -v `pwd`:/tmp --rm \
  -e OTEL_LOGS_EXPORTER=console \
  -e OTEL_TRACES_EXPORTER=console \
  -e OTEL_METRICS_EXPORTER=console \
  -e CATALINA_OPTS="$CATALINA_OPTS -javaagent:/tmp/opentelemetry-javaagent.jar" \
  -e JAVA_OPTS="-Dcom.sun.management.jmxremote         -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.rmi.port=9999 -Djava.rmi.server.hostname=0.0.0.0 -Dcom.sun.management.jmxremote.ssl=false -Dotel.jmx.target.system=tomcat" \     
  tomcat:9.0

该命令的输出将与运行 JMX scraper 的输出非常相似:

04-Sep-2025 21:43:40.251 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [48] milliseconds
[otel.javaagent 2025-09-04 21:43:40:787 +0000] [jmx_bean_finder] INFO io.opentelemetry.javaagent.shaded.instrumentation.jmx.engine.MetricRegistrar - Created Counter for tomcat.error.count
[otel.javaagent 2025-09-04 21:43:40:787 +0000] [jmx_bean_finder] INFO io.opentelemetry.javaagent.shaded.instrumentation.jmx.engine.MetricRegistrar - Created Counter for tomcat.request.count
[otel.javaagent 2025-09-04 21:43:40:789 +0000] [jmx_bean_finder] INFO io.opentelemetry.javaagent.shaded.instrumentation.jmx.engine.MetricRegistrar - Created Gauge for tomcat.request.duration.max
[otel.javaagent 2025-09-04 21:43:40:789 +0000] [jmx_bean_finder] INFO io.opentelemetry.javaagent.shaded.instrumentation.jmx.engine.MetricRegistrar - Created Counter for tomcat.request.duration.sum
[otel.javaagent 2025-09-04 21:43:40:789 +0000] [jmx_bean_finder] INFO io.opentelemetry.javaagent.shaded.instrumentation.jmx.engine.MetricRegistrar - Created Counter for tomcat.network.io
[otel.javaagent 2025-09-04 21:43:40:789 +0000] [jmx_bean_finder] INFO io.opentelemetry.javaagent.shaded.instrumentation.jmx.engine.MetricRegistrar - Created Counter for tomcat.network.io
[otel.javaagent 2025-09-04 21:43:40:790 +0000] [jmx_bean_finder] INFO io.opentelemetry.javaagent.shaded.instrumentation.jmx.engine.MetricRegistrar - Created UpDownCounter for tomcat.thread.count
[otel.javaagent 2025-09-04 21:43:40:790 +0000] [jmx_bean_finder] INFO io.opentelemetry.javaagent.shaded.instrumentation.jmx.engine.MetricRegistrar - Created UpDownCounter for tomcat.thread.limit
[otel.javaagent 2025-09-04 21:43:40:791 +0000] [jmx_bean_finder] INFO io.opentelemetry.javaagent.shaded.instrumentation.jmx.engine.MetricRegistrar - Created UpDownCounter for tomcat.thread.busy.count

如果我们的部署已经在使用 OpenTelemetry Java 代理,现在我们就有了一种无需引入额外工具即可收集 JMX 指标的方法。但如果我们更倾向于使用外部工具,那该怎么办呢?别担心,OpenTelemetry 这把“瑞士军刀”已经为你准备好了!

使用 OpenTelemetry Collector 和 JMX receiver

我们将要探讨的最后一种将JMX指标转换为 OpenTelemetry 的方法是使用 OpenTelemetry Collector。Collector 提供了许多集成功能,通常作为遥测管道的一部分部署在基础设施内部。Collector 由许多组件构成,其中之一是 JMX receiver,它在底层使用 JMX scraper 与 Java 应用程序进行交互。

在本示例中,我们将继续使用之前一直在用的 tomcat 应用程序,并使用由社区发布和维护的 OpenTelemetry Collector Contrib 发行版。运行带有调试导出器的 Collector 需要以下配置文件,该调试导出器会将指标输出到控制台。由于 Collector 便于配置多个导出器,我们还添加了一个 OpenTelemetry 协议(OTLP)导出器,用于将数据发送到 Honeycomb(译者注:一个可观测性云厂商):

receivers:
  jmx/tomcat:
    jar_path: /tmp/opentelemetry-jmx-scraper-1.48.0-alpha.jar
    endpoint: localhost:9999
    target_system: tomcat
    collection_interval: 10s


exporters:
  otlphttp:
    endpoint: https://api.honeycomb.io:443
    headers:
      x-honeycomb-team: ${env:HONEYCOMB_API_KEY}
      x-honeycomb-dataset: jmx-test
   
  debug:
    verbosity: detailed


service:
  telemetry:
    logs:
      level: debug
  pipelines:
    metrics:
      receivers: [jmx/tomcat]
      exporters: [debug, otlphttp]

请注意,要使此配置生效,我们需要指定 JMX 抓取器 JAR 的位置,因为接收器本身并不包含该 JAR。有了这份配置,以下命令将下载最新发布的 Collector Contrib 发行版并运行它:

$ wget https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.133.0/otelcol-contrib_0.133.0_darwin_arm64.tar.gz -O - | tar -xz
​​$ ./otelcol-contrib --config configuration.yaml

收集器的输出将包含来自JMX抓取器的详细信息以及来自调试导出器的日志,以验证数据是否按照配置进行导出。

使用 Collector 使我们能够收集指标,而无需修改应用程序或应用程序运行的环境,只要该应用程序远程暴露 JMX 端口即可。 Collector 还增加了一些灵活性,可以根据需要对数据进行转换或丰富。

自定义应用的监控采集

OpenTelemetry 社区支持的应用程序列表不足以处理所有现有的Java应用程序。幸运的是,可以定义自定义规则配置文件来支持自定义应用程序。该项目的官方文档更详细地描述了编写自定义配置的语法。在下面的示例中,我们创建的规则为Resin服务器暴露的指标提供了映射。此配置将resin命名空间中ThreadPool托管Bean(MBean)的JMX属性ThreadActiveCount映射到OpenTelemetry中名为resin.threadpool.active.count的 gauge(量规):

rules:
 - bean: resin:type=ThreadPool
   type: gauge
   unit: "{thread}"
   mapping:
     ThreadActiveCount:
       metric: resin.threadpool.active.count
       desc: "Current number of active threads in the pool"

将OpenTelemetry与JMX集成的每种方法都支持自定义配置文件。JMX抓取器通过otel.jmx.config属性来支持这一点。收集器中的JMX接收器可以使用jmx_configs而非target_system进行配置。允许收集器使用此自定义文件的配置如下:

receivers:
  jmx/resin:
    jar_path: /Users/alex/Downloads/opentelemetry-jmx-scraper-1.48.0-alpha.jar
    endpoint: localhost:9999
    jmx_configs: /tmp/resin.rules.yaml
    collection_interval: 10s

总结

有了这些,我们现在就具备了将生成JMX遥测数据的应用程序集成到任何支持 OpenTelemetry 的遥测管道中的工具。可以灵活选择使用JMX抓取器、Java代理或收集器,这确保我们能够选用适合自身环境的工具,同时对现有工作流程的影响降至最低。

原文链接:https://www.honeycomb.io/blog/integrating-jmx-opentelemetry

快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云
OpenSource
开源版
Flashcat
Flashcat