从 JVM 到全链路:高并发系统性能监控与调优实战指南

25 年 12 月 7 日 星期日
2910 字
15 分钟

摘要

本文从 JVM 内存模型与 GC 机制切入,梳理中间件、数据库、压测报表等关键监控指标,演示 jvisualvm、jconsole 及 jstat/jmap/jstack 等工具的使用方法,给出可落地的 JVM 调优参数与排查思路,帮助读者建立高并发系统性能监控与问题定位的完整方法论。

1. JVM 内存模型

  • 程序计数器 Program Counter Register:
    • 记录的是正在执行的虚拟机字节码指令的地址,
    • 此内存区域是唯一一个在JAVA虚拟机规范中没有规定任何OutOfMemoryError的区域
  • 虚拟机:VM Stack
    • 描述的是 JAVA 方法执行的内存模型,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法接口等信息
    • 局部变量表存储了编译期可知的各种基本数据类型、对象引用
    • 线程请求的栈深度不够会报 StackOverflowError 异常
    • 栈动态扩展的容量不够会报 OutOfMemoryError 异常
    • 虚拟机栈是线程隔离的,即每个线程都有自己独立的虚拟机栈
  • 本地方法:Native Stack
    • 本地方法栈类似于虚拟机栈,只不过本地方法栈使用的是本地方法
  • 堆:Heap
    • 几乎所有的对象实例都在堆上分配内存

2. 堆

所有的对象实例以及数组都要在堆上分配。堆是垃圾收集器管理的主要区域,也被称为“GC堆”;也是我们优化最多考虑的地方。
堆可以细分为:

  • 新生代
    • Eden 空间
    • From Survivor 空间
    • To Survivor 空间
  • 老年代
  • 永久代/元空间
    • Java8 以前永久代,受 jvm 管理,java8 以后元空间,直接使用物理内存。因此,默认情况下,元空间的大小仅受本地内存限制。

垃圾回收 从 Java8 开始,HotSpot 已经完全将永久代(Permanent Generation)移除,取而代之的是一个新的区域—元空间(MetaSpace)

3. jconsole 与 jvisualvm

Jdk 的两个小工具 jconsole、jvisualvm(升级版的 jconsole);通过命令行启动,可监控本地和远程应用。远程应用需要配置。

3.1 jvisualvm 能干什么

监控内存泄露,跟踪垃圾回收,执行时内存、cpu 分析,线程分析...
运行:正在运行的
休眠:sleep
等待:wait
驻留:线程池里面的空闲线程
监视:阻塞的线程,正在等待锁

3.2 安装插件方便查看 gc

  • Cmd 启动 jvisualvm
  • 工具->插件
  • 如果 503 错误解决:

4. 监控指标

4.1 中间件指标

常用的中间件例如Tomcat, Weblogic等指标主要包括JVM,ThreadPool,JDBC具体如下:

一级指标 二级指标 单位 解释
GC GC频率 每秒多少次 java虚拟机垃圾部分回收频率
Full GC频率 每小时多少次 java虚拟机垃圾部分回收频率
Full GC平均时长 秒 用于垃圾完全回收的平均时长
Full GC最大时长 秒 用于垃圾回收的最大时长
堆使用频率 个 堆使用率
ThreadPool Active Thread Count 个 活动的线程数
Pending User Request 个 处于排队的用户请求个数
JDBC JDBC Active Collection 个 JDBC活动连接数
  • 当前正在运行的线程数不能超过设定的最大值。一般情况下系统性能较好的情况下,线程数最小值设置 50 和最大值设置 200 比较合适。
  • 当前运行的 JDBC 连接数不能超过设定的最大值。一般情况下系统性能较好的情况下,JDBC 最小值设置 50 和最大值设置 200 比较合适。
  • GC频率不能频繁,特别是 FULL GC 更不能频繁,一般情况下系统性能较好的情况下,JVM 最小堆大小和最大堆大小分别设置 1024M 比较合适。

4.2 数据库指标

常用的数据库例如MySql指标主要包括SQL、吞吐量、缓存命中率、连接数等,具体如下:

一级指标 二级指标 单位 解释
SQL 耗时 微秒 执行SQL耗时
吞吐量 QPS 个 每秒查询次数
TPS 个 每秒事务次数
命中率 Key Buffer命中率 百分之 索引缓冲区命中率
InnoDB Buffer命中率 百分之 InnoDB缓冲区命中率
Query Cache命中率 百分之 查询缓存命中率
Table Cache命中率 百分之 表缓存命中率
Thread Cache命中率 百分之 线程缓存命中率
锁 等待次数 次 锁等待次数
等待时间 微秒 锁等待时间
  • SQL 耗时越小越好,一般情况下微秒级别。
  • 命中率越高越好,一般情况下不能低于 95%。
  • 锁等待次数越低越好,等待时间越短越好。
压测内容压测线程数吞吐量/s90%响应时间99%响应时间
Nginx50233511944
Gateway5010367831
简单服务5011341817
首页一级菜单渲染50270(db,thymeleaf)267365
首页渲染(开缓存)50290251365
首页渲染(开缓存、 优化数据库、关日 志)50700105183
三级分类数据获取502(db)/8(加索引)......
三级分类(优化业 务)50111571896
三 级 分 类 ( 使 用 redis 作为缓存)50411153217
首页全量数据获取507(静态资源)
Nginx+Gateway50
Gateway+简单服务50312630125
全链路5080088310
  • 中间件越多,性能损失越大,大多都损失在网络交互了;
  • 业务:
    • Db(MySQL 优化)
    • 模板的渲染速度(缓存)
    • 静态资源

5. JVM 分析&调优

JVM调优,调的是稳定,并不能带给你性能的大幅提升。服务稳定的重要性就不用多说了,保证服务的稳定,gc 永远会是 Java 程序员需要考虑的不稳定因素之一。复杂和高并发下的服务,必须保证每次 gc 不会出现性能下降,各种性能指标不会出现波动,gc 回收规律而且干净,找到合适的 jvm 设置。Full gc 最会影响性能,根据代码问题,避免full gc 频率。可以适当调大年轻代容量,让大对象可以在年轻代触发 yong gc,调整大对象在年轻代的回收频次,尽可能保证大对象在年轻代回收,减小老年代缩短回收时间;

5.1 几个常用工具

命令功能描述
jstack查看 jvm 线程运行状态,是否有死锁现象等等信息
jinfo可以输出并修改运行时的 java 进程的 opts。
jps与 unix 上的 ps 类似,用来显示本地的 java 进程,可以查看本地运行着几个java程序,并显示他们的进程号。
jstat一个极强的监视 VM 内存工具。可以用来监视 VM 内存内的各种堆和非堆的大小及其内存使用量。
jmap打印出某个 java 进程(使用 pid)内存内的所有'对象'的情况(如:产生那些对象,及其数量)

5.2 命令示例

jstat 工具特别强大,有众多的可选项,详细查看堆内各个部分的使用量,以及加载类的数量。使用时,需加上查看进程的进程 id,和所选参数。
jstat -class pid 显示加载 class 的数量,及所占空间等信息
jstat -compiler pid 显示 VM 实时编译的数量等信息。
jstat -gc pid 可以显示 gc 的信息,查看 gc 的次数,及时间
jstat -gccapacity pid 堆内存统计,三代(young,old,perm)内存使用和占用大小
jstat -gcnew pid 新生代垃圾回收统计
jstat -gcnewcapacity pid 新生代内存统计
jstat -gcold pid 老年代垃圾回收统计
除了以上一个参数外,还可以同时加上 两个数字,如:jstat -printcompilation 3024 250 6 是每 250 毫秒打印一次,一共打印 6 次,还可以加上-h3 每三行显示一下标题。
jstat -gcutil pid 1000 100 : 1000ms 统计一次 gc 情况统计 100 次;
在使用这些工具前,先用 JPS 命令获取当前的每个 JVM 进程号,然后选择要查看的JVM。
jinfo 是 JDK 自带的命令,可以用来查看正在运行的 java 应用程序的扩展参数,包括JavaSystem 属性和 JVM 命令行参数;也可以动态的修改正在运行的 JVM 一些参数。当系统崩溃时,jinfo 可以从 core 文件里面知道崩溃的 Java 应用程序的配置信息
jinfo pid 输出当前 jvm 进程的全部参数和系统属性
jinfo -flag name pid 可以查看指定的 jvm 参数的值;打印结果:-无此参数,+有
jinfo -flag [+|-]name pid 开启或者关闭对应名称的参数(无需重启虚拟机)
jinfo -flag name=value pid 修改指定参数的值
jinfo -flags pid 输出全部的参数
jinfo -sysprops pid 输出当前 jvm 进行的全部的系统属性
jmap 可以生成 heap dump 文件,也可以查看堆内对象分析内存信息等,如果不使用这个命令,还可以使用-XX:+HeapDumpOnOutOfMemoryError 参数来让虚拟机出现OOM的时候自动生成 dump 文件。
jmap -dump:live,format=b,file=dump.hprof pid dump 堆到文件,format 指定输出格式,live 指明是活着的对象,file 指定文件名。eclipse 可以打开这个文件
jmap -heap pid 打印 heap 的概要信息,GC 使用的算法,heap 的配置和使用情况,可以用此来判断内存目前的使用情况以及垃圾回收情况
jmap -finalizerinfo pid 打印等待回收的对象信息
jmap -histo:live pid 打印堆的对象统计,包括对象数、内存大小等。jmap -histo:live这个命令执行,JVM 会先触发 gc,然后再统计信息
jmap -clstats pid 打印 Java 类加载器的智能统计信息,对于每个类加载器而言,对于每个类加载器而言,它的名称,活跃度,地址,父类加载器,它所加载的类的数量和大小都会被打印。此外,包含的字符串数量和大小也会被打印。
jmap -F -histo pid -F 强制模式。如果指定的 pid 没有响应,请使用 jmap -dump 或jmap -histo 选项。此模式下,不支持 live 子选项。
jstack 是 jdk 自带的线程堆栈分析工具,使用该命令可以查看或导出 Java 应用程序中线程堆栈信息。
jstack pid 输出当前 jvm 进程的全部参数和系统属性

5.3 调优项

官方文档

文章标题:从 JVM 到全链路:高并发系统性能监控与调优实战指南

文章作者:子木

文章链接:https://blog.zimutool.cn/posts/architecture/performance-monitor[复制]

最后修改时间:


商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,您可以自由地在任何媒体以任何形式复制和分发作品,也可以修改和创作,但是分发衍生作品时必须采用相同的许可协议。
本文采用CC BY-NC-SA 4.0进行许可。