Nightingale 集成指南:Java/JVM 监控仪表盘(JMX Exporter 与 OpenTelemetry 双采集链路)
【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale
Nightingale 的integrations/Java目录为 Java 应用提供了一组可直接导入的 Prometheus 数据源 JVM 仪表盘,覆盖堆内存、内存池、GC、线程、类加载、进程与物理内存等核心指标。本指南以该目录下的 README 为核心,完整讲解「Prometheus JMX Exporter」与「OpenTelemetry Java Agent」两条采集链路的部署步骤、Categraf 抓取配置、指标验证方法,并结合仓库内的仪表盘 JSON 与国际化文件,说明每张仪表盘依赖的指标族与标签约束。读完本文,你可以独立完成 Java 进程的指标采集、验证与仪表盘导入。
两类仪表盘,两套指标族,不能混用
目录 integrations/Java/dashboards 下共存放三张仪表盘,按采集方式分为两类,指标命名完全不同:
| 仪表盘文件 | 采集方式 | 关键指标 |
|---|---|---|
jmx_by_exporter.json(JMX) | Prometheus JMX Exporter | jmx_exporter_build_info、jvm_memory_*、jvm_gc_collection_seconds_* |
jmx_by_kubernetes.json(JMX - Kubernetes) | Prometheus JMX Exporter(K8s 标签体系) | 同上,但使用namespace/container/pod标签 |
jvm_by_opentelementry.json(JVM by OpenTelemetry) | OpenTelemetry Java Agent → OTel Collector | jvm_cpu_count、jvm_memory_used_bytes、jvm_gc_duration_seconds_*等 OTel 命名 |
由于两种链路产出的指标名与标签结构不同,混用会导致面板查询无数据。选择仪表盘之前,必须先确认线上 Java 进程实际使用的是哪条采集链路。
链路一:Prometheus JMX Exporter
JMX Exporter 是 Prometheus 官方维护的 Java Agent,通过 JMX(Java Management Extensions)读取 JVM 运行时数据并以/metrics暴露。
1. 为 Java 进程加载 Agent 并监听端口
以 9404 端口为例,启动命令大致为:
java -javaagent:/opt/jmx_prometheus_javaagent.jar=9404:/opt/config.yaml -jar app.jar参数含义:-javaagent指定 agent 包路径;=9404:config.yaml表示监听 9404 端口并使用指定的 JMX 抓取规则配置文件。Agent 启动后,http://127.0.0.1:9404/metrics即为 Prometheus 格式的指标端点。
2. 新建 Categraf 抓取配置
在 Categraf 的conf/input.prometheus/目录下新建java-jmx.toml,内容如下:
# conf/input.prometheus/java-jmx.toml [[instances]] urls = ["http://127.0.0.1:9404/metrics"] url_label_key = "instance" url_label_value = "{{.Host}}" labels = { job = "order-service" }各字段作用:
urls:JMX Exporter 暴露的指标地址,抓取后会为每条时序自动附加instance标签(url_label_key/url_label_value指定标签名与取值,{{.Host}}会替换为目标主机名);labels:附加的静态标签,这里用job = "order-service"标识业务服务。
3. 先验证,再导入仪表盘
配置完成后先确认指标确实存在:
curl -fsS http://127.0.0.1:9404/metrics \ | grep -E 'jmx_exporter_build_info|jvm_memory_pool_bytes_used' \ | head出现jmx_exporter_build_info与jvm_memory_pool_bytes_used说明 Agent 正常、指标名与仪表盘预期一致,此时再导入JMX仪表盘。
4. 为什么必须保留 job 和 instance 标签
打开 jmx_by_exporter.json 的var段可以看到两张 JMX 仪表盘的变量定义:
{ "name": "job", "definition": "label_values(jmx_exporter_build_info,job)" }, { "name": "instance", "definition": "label_values(jmx_exporter_build_info{job=\"$job\"},instance)" }仪表盘的所有面板(如up{job="$job", instance="$instance"}、jvm_memory_used_bytes{area="heap",job="$job",instance="$instance"})都通过job、instance两个标签筛选数据,因此 Categraf 配置中的job静态标签与instance标签必须保留,否则下拉框取不到值、面板全部为空。
5. JMX 仪表盘包含哪些面板
从 JSON 的panels结构看,JMX仪表盘按行分组,覆盖以下监控面:
- Basic Info:
Status(up的 UP/DOWN 映射)、Uptime(time() - process_start_time_seconds)、Available CPUs(os_available_processors)、Open file descriptors(os_open_file_descriptor_count); - JVM Memory:heap 与 nonheap 的
jvm_memory_used_bytes、jvm_memory_bytes_max; - Memory Pool:按 pool 分组展示
jvm_memory_pool_bytes_used/committed/max,覆盖CodeHeap 'non-nmethods'、CodeHeap 'profiled nmethods'、CodeHeap 'non-profiled nmethods'、Eden、Compressed Class Space、Survivor、Old Gen(正则匹配PS Old Gen|G1 Old Gen|Tenured Gen)、Metaspace,兼容 G1、Parallel 等常见垃圾回收器; - GC:过去一分钟 GC 耗时(
increase(jvm_gc_collection_seconds_sum[1m]))、GC 次数(increase(jvm_gc_collection_seconds_count[1m]))、每次 GC 平均耗时(两者相除); - Threads and Class loading:
jvm_threads_current/daemon/deadlocked、jvm_classes_loaded_total; - Physical memory:
os_total_physical_memory_bytes、os_committed_virtual_memory_bytes、os_free_physical_memory_bytes。
6. Kubernetes 场景:JMX - Kubernetes 仪表盘
如果 Java 服务运行在 Kubernetes 中,应使用 jmx_by_kubernetes.json。从该文件var段可以看到,它的变量体系不同:
{ "name": "namespace", "definition": "label_values(jmx_exporter_build_info, namespace)" }, { "name": "service", "definition": "label_values(jmx_exporter_build_info{namespace=\"$namespace\"},container)" }, { "name": "pod", "definition": "label_values(jmx_exporter_build_info{namespace=\"$namespace\", container=\"$service\"},pod)" }面板查询相应改为up{namespace="$namespace", container="$service", pod="$pod"}、jvm_memory_used_bytes{namespace="$namespace", container="$service", pod="$pod"}等,并额外引入container_spec_cpu_quota、container_file_descriptors这类容器维度指标。这意味着采集端(如 Kubelet / cadvisor 或带namespace/container/pod标签的抓取方式)必须补齐这三类标签,仪表盘才能工作。
链路二:OpenTelemetry Java Agent
OpenTelemetry Java Agent 通过字节码注入自动采集 JVM 运行时指标,并按照 OTel 语义约定命名,与 JMX Exporter 的命名风格(jvm_memory_pool_bytes_used等)完全不同。文档记录的实机验证环境为:OpenTelemetry Java Agent 2.28.1、OTLP gRPC 协议、OTel Collector 中转。
1. 通过环境变量启动 Java 进程
export JAVA_TOOL_OPTIONS="-javaagent:/opt/opentelemetry-javaagent.jar" export OTEL_SERVICE_NAME="order-service" export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4317" export OTEL_EXPORTER_OTLP_PROTOCOL="grpc" export OTEL_METRICS_EXPORTER="otlp" java -jar app.jar环境变量说明:
JAVA_TOOL_OPTIONS:JVM 启动时自动附加 agent(-javaagent路径需替换为你实际存放 jar 的位置);OTEL_SERVICE_NAME:服务名,会作为service.name资源属性上报;OTEL_EXPORTER_OTLP_ENDPOINT:OTLP 上报地址,此处指向 OTel Collector 的 gRPC 端口4317;OTEL_EXPORTER_OTLP_PROTOCOL:传输协议固定为grpc;OTEL_METRICS_EXPORTER:只启用otlp指标导出(如同时需要 trace,可追加逗号分隔的其他 exporter)。
2. OTel Collector 最小配置:把 OTLP 转成 Prometheus
新建otel-collector.yaml:
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 processors: batch: {} exporters: prometheus: endpoint: 0.0.0.0:9464 service: pipelines: metrics: receivers: [otlp] processors: [batch] exporters: [prometheus]链路为:Java Agent → OTLP gRPC(4317)→ Collectorbatch处理器 → Prometheus exporter(9464)。Collector 的 Prometheus exporter 会把 OTel 指标转写为 Prometheus 文本格式,供 Categraf 抓取。
3. Categraf 抓取 Collector
# conf/input.prometheus/java-otel.toml [[instances]] urls = ["http://otel-collector:9464/metrics"] url_label_key = "instance" url_label_value = "{{.Host}}" labels = { job = "java-otel" }注意此处urls指向的是OTel Collector 的 9464 端口,而不是 Java 进程本身。
4. 验证 OTel 指标后再导入仪表盘
抓取前先确认目标指标存在:
curl -fsS http://otel-collector:9464/metrics \ | grep -E 'jvm_memory_used_bytes|jvm_gc_duration_seconds' \ | headJVM by OpenTelemetry仪表盘(jvm_by_opentelementry.json)依赖的指标与 JMX 版本有明显差异,从面板查询可以归纳出:
- CPU:
jvm_cpu_count、jvm_cpu_recent_utilization_ratio(瞬时使用率,乘 100 归一化为百分比)、jvm_cpu_time_seconds_total增量计算的平均使用率; - 内存:
jvm_memory_used_bytes、jvm_memory_committed_bytes、jvm_memory_limit_bytes、jvm_memory_used_after_last_gc_bytes,且用jvm_memory_type="heap"|"non_heap"区分堆内外,用{{jvm_memory_pool_name}}做 legend 区分内存池; - GC:
jvm_gc_duration_seconds_sum/count的 1 分钟增量,以及histogram_quantile(0.95, ...)计算的单次 GC 耗时 P95,legend 使用{{jvm_gc_action}}、{{jvm_gc_name}}; - 线程与类加载:
jvm_thread_count(按jvm_thread_daemon、jvm_thread_state分组)、jvm_class_count、jvm_class_loaded_total、jvm_class_unloaded_total。
该仪表盘的变量定义同样基于指标反查:job来自label_values(jvm_class_count, job),instance来自label_values(jvm_class_count{job="$job"}, instance)。因此 OTel 链路的 Categraf 配置同样必须保留job与instance标签。目录下的 i18n/en_US.json 还说明这些面板文案(如"上次 GC 后 Heap 使用率""过去 1 分钟单次 GC 耗时 95 分位值")均按 OpenTelemetry JVM 语义约定命名,与仪表盘指标一一对应。
指标命名差异与选型建议
文档末尾特别强调:Micrometer、JMX Exporter 和 OTel Java Agent 的指标命名不同,应选择与采集链路对应的模板。三者典型差异如下:
| 采集方式 | 内存示例 | GC 示例 | 适用模板 |
|---|---|---|---|
| Prometheus JMX Exporter | jvm_memory_pool_bytes_used | jvm_gc_collection_seconds_* | JMX/JMX - Kubernetes |
| OpenTelemetry Java Agent | jvm_memory_used_bytes{jvm_memory_type="heap"} | jvm_gc_duration_seconds_* | JVM by OpenTelemetry |
| Micrometer(Spring Boot Actuator 等) | jvm_memory.used等 Micrometer 命名 | jvm_gc.pause等 | 需另找对应模板,不可直接套用 |
因此落地时的推荐流程是:
- 确认 Java 进程实际使用的采集组件(JMX Exporter / OTel Java Agent / Micrometer),三种并存时尤其要区分清楚;
- 按对应链路完成 Agent 或 Collector 部署,并配置 Categraf
input.prometheus抓取; - 用
curl验证关键指标名与job、instance(K8s 场景为namespace、container、pod)标签齐全; - 最后再导入与指标族匹配的仪表盘 JSON,导入后通过变量下拉框确认能列出目标 job/instance,面板即可出数。
仓库中三张仪表盘 jmx_by_exporter.json、jmx_by_kubernetes.json、jvm_by_opentelementry.json 均以 Prometheus 为数据源(面板中datasourceCate为prometheus,通过${prom}变量引用),导入时选择对应的 Prometheus 数据源即可直接使用,无需修改面板表达式。
【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考