文章

Jvm-指标收集

收集指标

1
JMX Exporter

JMX Exporter 简介

Java Management Extensions,JMX 是管理 Java 的一种扩展框架,JMX Exporter 基于此框架读取 JVM 的运行时状态。JMX Exporter 利用 Java 的 JMX 机制来读取 JVM 运行时的监控数据,然后将其转换为 Prometheus 可辨识的 metrics 格式,以便让 Prometheus 对其进行监控采集。

启动方式

启动独立进程

JVM 启动时指定参数,暴露 JMX 的 RMI 接口。JMX Exporter 调用 RMI 获取 JVM 运行时状态数据,转换为 Prometheus metrics 格式,并暴露端口让 Prometheus 采集。

备注: 官方不建议使用启动独立进程方式

JVM 进程内启动(in-process)

JVM 启动时指定参数,通过 javaagent 的形式运行 JMX Exporter 的 jar 包,进程内读取 JVM 运行时状态数据,转换为 Prometheus metrics 格式,并暴露端口让 Prometheus 采集

启用 jmx-exporter

1.下载jar包

JMX Exporter

选择需要版本: 一般选最新版本 Image

复制链接: jmx_prometheus_javaagent-1.0.1.jar Image

2.启动命令

获取两个文件的绝对或相对路径

  1. jar包: /data/jmx_prometheus_javaagent-1.0.1.jar
  2. 配置文件: /data/jmx-config.yaml
    1
    
    java -javaagent:/data/jmx_prometheus_javaagent-1.0.1.jar=8080:/data/config.yaml -jar yourJar.jar
    

8080: 暴露指标的接口

jmx-config.yaml

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
36
37
38
39
40
41
42
43
44
---
lowercaseOutputLabelNames: true
lowercaseOutputName: true
whitelistObjectNames: 
  - "java.lang:*"  # 抓取 JVM 通用的 MBeans
  - "com.sun.management:type=HotSpotDiagnostic"  # 热点 JVM 特定的 MBeans
  - "com.zaxxer.hikari:type=Pool (apollo*)"  # 抓取 Apollo 中 HikariCP 连接池的 MBeans

rules:
  # 匹配 JVM 内存相关的指标
  - pattern: "java.lang:type=MemoryPool,name=(.*)"
    name: jvm_memory_pool_$1
    type: GAUGE
    labels: {}
    help: "JVM memory pool"

  - pattern: "java.lang:type=GarbageCollector,name=(.*)"
    name: jvm_gc_$1
    type: COUNTER
    labels: {}
    help: "JVM Garbage Collection"

  # 匹配线程信息
  - pattern: "java.lang:type=Threading"
    name: jvm_threads
    type: GAUGE
    attrNameSnakeCase: true
    help: "JVM Threads"

  # 匹配操作系统级的 CPU 使用和内存信息
  - pattern: "java.lang:type=OperatingSystem"
    name: os_$1
    type: GAUGE
    labels: {}
    attrNameSnakeCase: true
    help: "Operating System Metrics"

  # 匹配 HikariCP 连接池的指标(如果 Apollo 使用 HikariCP)
  - pattern: "com.zaxxer.hikari:type=Pool (.*),name=.*,.*=(.*)"
    name: hikari_pool_$1_$2
    type: GAUGE
    labels: {}
    help: "HikariCP connection pool metrics"

1
2
3
4
type: 规则其他常见类型
   COUNTER:计数器类型,只会递增,比如请求次数、错误次数。
   HISTOGRAM:统计一段时间内的值分布(包括计数和观察到的样本)。
   SUMMARY:类似于 HISTOGRAM,但更多地用于计算分位数。

使用jconsole 或 jvisualvm 连接远程 JVM

安装依赖环境-java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# MacOS:
brew install openjdk@11

## 安装后,根据提示,设置环境
echo 'export PATH="/opt/homebrew/opt/openjdk@11/bin:$PATH"' >> /Users/FengYLBook/.bash_profile

export CPPFLAGS="-I/opt/homebrew/opt/openjdk@11/include"

sudo ln -sfn /opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk


# Linux:
apt install openjdk-11-jdk
yum install openjdk-11-jdk

服务端开启 jmx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 保证java开启了JMX,启动参数

-Dcom.sun.management.jmxremote  # 启用 JMX
-Dcom.sun.management.jmxremote.port=PORT  # 设定远程 JMX 监听端口(需要替换为实际端口号,如 12345)
-Dcom.sun.management.jmxremote.rmi.port=PORT  # 用于 RMI 连接的端口(通常和 JMX 端口相同)
-Dcom.sun.management.jmxremote.authenticate=false  # 禁用 JMX 认证(生产环境不建议禁用)
-Dcom.sun.management.jmxremote.ssl=false  # 禁用 SSL 加密(生产环境不建议禁用)
-Djava.rmi.server.hostname=HOST  # 绑定的主机名或 IP 地址(需要替换为实际的主机名或 IP 地址)


# eg:
-Dcom.sun.management.jmxremote  # 启用 JMX
-Dcom.sun.management.jmxremote.port=8080
-Dcom.sun.management.jmxremote.rmi.port=8080
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=172.31.25.29

启动 jconsole

1
2
# 终端执行
jconsole

Image

实践apollo接jmx-exporter

apollo 启动脚本更改

1
2
3
4
5
6
7
8
9
10
# /apollo-*/script/startup.sh
...

# 使用 eval 将系统环境变量 替换并覆盖 prometheus-jmx-config.yaml 中同名变量
# 如上 ${MY_SVC_NAME}、${MY_POD_NAME}、${POD_IP}
eval "cat <<EOF
$(< /prometheus-jmx-config.yaml )
EOF" > /prometheus-jmx-config.yaml

...

prometheus-jmx-config.yaml

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#hostPort: "apollo-configservice-hl.md:8080"  # 远程主机的IP和JMX监听端口(使用独立jmx-exporter进程连接远程 jvm进程时使用)
lowercaseOutputName: true
lowercaseOutputLabelNames: true
#whitelistObjectNames:
#  - "java.lang<type=(.*)>"  # 抓取 JVM 通用的 MBeans
#  - "com.sun.management:type=HotSpotDiagnostic"  # JVM 特定的 MBeans

rules:
  # 匹配 JVM 内存相关的指标
  - pattern: "java.lang<type=MemoryPool, name=(.+)><(.+)>(.+):(.+)"
    name: jvm_memory_pool_\$2_\$3
    type: GAUGE
    labels:
      application: "${MY_SVC_NAME}"
      pool: "\$1"
      pod_name: "${MY_POD_NAME}"
      pod_ip: "${POD_IP}"
    help: "JVM memory pool"

  - pattern: "java.lang<type=Runtime>(.+)"
    name: process_uptime_seconds
    labels:
      application: "${MY_SVC_NAME}"
      pod_name: "${MY_POD_NAME}"
      pod_ip: "${POD_IP}"
    type: GAUGE
    attrNameSnakeCase: true # 将属性名转换为蛇形命名
    help: "Process uptime in seconds"
    
  - pattern: "java.lang<type=GarbageCollector, name=(.+)><>CollectionCount"
    name: jvm_gc_collectioncount
    type: COUNTER
    labels:
      name: "\$1"
      application: "${MY_SVC_NAME}"
      pod_name: "${MY_POD_NAME}"
      pod_ip: "${POD_IP}"
    help: "JVM Garbage Collection"

  - pattern: "java.lang<type=GarbageCollector, name=(.+)><>CollectionTime"
    name: jvm_gc_collectiontime
    type: COUNTER
    labels:
      name: "\$1"
      application: "${MY_SVC_NAME}"
      pod_name: "${MY_POD_NAME}"
      pod_ip: "${POD_IP}"
    help: "JVM Garbage Collection"

  - pattern: "java.lang<type=GarbageCollector, name=(.+), key=(.+)><LastGcInfo, (.+)>(.+)"
    name: jvm_gc_lastgcinfo
    labels:
      name: "\$1"
      key: "\$2"
      status: "\$3"
      application: "${MY_SVC_NAME}"
      pod_name: "${MY_POD_NAME}"
      pod_ip: "${POD_IP}"
    help: "JVM Garbage Collection"

  # 匹配线程信息
  - pattern: "java.lang<type=Threading>(.+)"
    name: jvm_threads
    labels:
      application: "${MY_SVC_NAME}"
      pod_name: "${MY_POD_NAME}"
      pod_ip: "${POD_IP}"
    type: GAUGE
    attrNameSnakeCase: true
    help: "JVM Threads"

  # 匹配操作系统级的 CPU 使用和内存信息
  - pattern: "java.lang<type=OperatingSystem>(.+)"
    name: os_system
    labels:
      application: "${MY_SVC_NAME}"
      pod_name: "${MY_POD_NAME}"
      pod_ip: "${POD_IP}"
    type: GAUGE
    attrNameSnakeCase: true
    help: "Operating System Metrics"

apollo 服务启动引用

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
# 以 k8s pod 为准 接入 apollo-configservice
spec:
  template:
    metadata:
      labels:
        app: apollo-configservice
    spec:
      containers:
      - env:
        - name: POD_IP
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: status.podIP
        - name: MY_POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: MY_SVC_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.labels['app']
        - name: JAVA_OPTS
          value: ...
            -javaagent:/apollo-configservice/jmx_prometheus_javaagent-1.0.1.jar=8080:/prometheus-jmx-config.yaml
            ...
本文由作者按照 CC BY 4.0 进行授权