介绍
尽管 Java 的性能和底层编译型语言没有太大区别,但您可能仍需要调整(Java 虚拟机)JVM 性能以满足应用程序的需求。在可扩展性和性能方面,应用程序的需求和要求可能会有所不同,这时需要持续监控您的 JVM 性能(一些关键指标——内存使用、垃圾收集和线程),以相应地对其进行调整。
我们可以通过使用 JMX Exporter 将应用程序 JMX 对象暴露给 Prometheus 并在 Grafana 中创建所需的图表来监控这些指标。为此,请按照以下步骤操作。
一般 Java 集成 Prometheus 监控指标有两种方式。一种是依赖中引入,另外一种是通过agent执行。
依赖引入
io.prometheussimpleclient0.15.0
io.prometheussimpleclient_hotspot0.15.0
io.prometheussimpleclient_httpserver0.15.0
io.prometheussimpleclient_pushgateway0.15.0
对于基于 Springboot 开发的 Java 框架,一定要引入micrometer-registry-prometheus
这个依赖, Spring Boot使用 Micrometer ,一个应用 metrics 组件,将 actuator metrics 整合到外部监控系统中。
它支持很多种监控系统,比如Netflix Atalas, AWS Cloudwatch, Datadog, InfluxData, SignalFx, Graphite, Wavefront和Prometheus等。
这时只需要在 application 配置文件中添加如下端口配置,即可对外暴露 JVM 指标。
management:health:db:enabled: falseserver:port: 8080endpoint:web:exposure:include: '*'exclude: envhealth:show-details: alwaysshutdown:enabled: falsemetrics:tags:application: ${spring.application.name}
agent 方式执行
下载 Java JMX Jar https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.15.0/jmx_prometheus_javaagent-0.15.0.jar
并将下载的 .jar 文件放在类路径中,具体路径可以自己设计,比如打到镜像特定路径下,或者放到 tomcat 服务指定路径下。
为您的应用程序配置 Config.yaml 文件
将 Jar 作为 Java 代理运行
java $JAVA_OPTS -javaagent:./jmx_prometheus_javaagent-0.13.0.jar=8080:config.yaml -Xlog:gc=debug:file=gc.txt -DApp.config.file=application.properties -cp "orderauditservice.jar: *” org.springframework.boot.loader.JarLauncher
具体如何采集除 JVM 之外的指标,请参考:https://github.com/prometheus/client_java
访问指标
现在可以通过http://localhost:8080/metrics访问指标
grafana可配置指标
使用 Prometheus 指标准备示例 Grafana 仪表盘,我们可以获取到已经抓取到的指标, springboot 提供了如下指标可用于grafana展示使用。
jvm.memory.max JVM最大内存
jvm.memory.committed JVM可用内存 是 展示并监控堆内存和Metaspace 重要
jvm.memory.used JVM已用内存 是 展示并监控堆内存和Metaspace 重要
jvm.buffer.memory.used JVM缓冲区已用内存
jvm.buffer.count 当前缓冲区数
jvm.threads.daemon JVM守护线程数 是 显示在监控页面
jvm.threads.live JVM当前活跃线程数 是 显示在监控页面;监控达到阈值时报警
jvm.threads.peak JVM峰值线程数 是 显示在监控页面
jvm.classes.loaded 加载classes数
jvm.classes.unloaded 未加载的classes数
jvm.gc.memory.allocated GC时,年轻代分配的内存空间
jvm.gc.memory.promoted GC时,老年代分配的内存空间
jvm.gc.max.data.size GC时,老年代的最大内存空间
jvm.gc.live.data.size FullGC时,老年代的内存空间
jvm.gc.pause GC耗时 是 显示在监控页面
tomcat.sessions.created tomcat已创建session数
tomcat.sessions.expired tomcat已过期session数
tomcat.sessions.active.current tomcat活跃session数
tomcat.sessions.active.max tomcat最多活跃session数 是 显示在监控页面,超过阈值可报警或者进行动态扩容 重要
tomcat.sessions.alive.max.second tomcat最多活跃session数持续时间
tomcat.sessions.rejected 超过session最大配置后,拒绝的session个数 是 显示在监控页面,方便分析问题
tomcat.global.error 错误总数 是 显示在监控页面,方便分析问题
tomcat.global.sent 发送的字节数
tomcat.global.request.max request最长时间
tomcat.global.request 全局request次数和时间
tomcat.global.received 全局received次数和时间
tomcat.servlet.request servlet的请求次数和时间
tomcat.servlet.error servlet发生错误总数
tomcat.servlet.request.max servlet请求最长时间
tomcat.threads.busy tomcat繁忙线程 是 显示在监控页面,据此检查是否有线程夯住
tomcat.threads.current tomcat当前线程数(包括守护线程) 是 显示在监控页面 重要
tomcat.threads.config.max tomcat配置的线程最大数 是 显示在监控页面 重要
tomcat.cache.access tomcat读取缓存次数
tomcat.cache.hit tomcat缓存命中次数
system.cpu.count CPU数量
system.load.average.1m load average 是 超过阈值报警 重要
system.cpu.usage 系统CPU使用率
process.cpu.usage 当前进程CPU使用率 是 超过阈值报警
http.server.requests http请求调用情况 是 显示10个请求量最大,耗时最长的URL;统计非200的请求量 重要
process.uptime 应用已运行时间 是 显示在监控页面
process.files.max 允许最大句柄数 是 配合当前打开句柄数使用
process.start.time 应用启动时间点 是 显示在监控页面
process.files.open 当前打开句柄数 是 监控文件句柄使用率,超过阈值后报警 重要
堆内存监控
在上图中,您可以看到平均堆使用量、最大堆使用量和最大分配堆内存, 如果您在特定时间观察到堆内存使用量突然激增,您可以将应用程序响应时间与请求数量相关联,并检查峰值是否是由于请求增加或代码自身问题导致。
GC监控
在上图中,您可以看到 min GC Count、max GC Count、min GC Time 和 max GC Time。GC 运行的频率,每次 GC 花费的时间。因此,当 GC 发生过于频繁或收集未引用对象所花费的时间太长时,它会影响您的应用程序的性能。这也可能是内存泄漏的另一个迹象,或者它可能只是意味着应用程序需要更多的堆空间。
Thread 监控
线程始终处于任何应用程序的中心阶段。线程负责服务用户请求。有足够的空闲线程来接受所有用户请求是很重要的。如果您没有足够的线程,这将增加用户请求的等待时间,进而增加应用程序响应时间。当线程需要较长时间来完成用户请求时,它会将引用的对象在堆内存中保存较长时间。这反过来会影响内存空间,并可能导致 OOM 或 GC 问题。
在上图中,您可以看到 Live、Demon 和 Deadlocked 线程数。
在上图中,您可以看到 Blocked、Waiting 和 Timed Waiting 线程计数。
总结
虽然框架已经为我们提供了各种指标,但是配置关键指标的使用仍然是一个复杂的过程,找出那些指标表明正在运行的应用程序的运行状况和性能,并在使用过程中不断优化和调整。
推荐
使用 Promethues 监控的一些实践
顶级的Kubernetes日志监控工具
原创不易,随手关注或者”在看“,诚挚感谢!