开发者
鲲鹏服务器上 Java 服务 GC 停顿排查与优化
鲲鹏服务器上 Java 服务 GC 停顿排查与优化
原创
发表于05/06
90

问题描述

将 Spring Boot 微服务从 x86 迁移到鲲鹏 920(64 核 / 256GB 内存),功能测试通过,但压测发现 GC 停顿时间明显增大。x86 上平均 GC 停顿 30ms,鲲鹏上达到 80-120ms,偶尔出现 500ms 以上的长停顿,导致 P99 延迟波动。

排查过程

# 查看当前使用的 JDK 版本
java -version

# 输出:
# openjdk version "17.0.8" 2023-07-18
# OpenJDK Runtime Environment (build 17.0.8+7)
# OpenJDK 64-Bit Server VM (build 17.0.8+7, mixed mode, sharing)

使用 G1 GC 日志分析停顿原因:

# 添加 GC 日志参数后重启
java -Xms16g -Xmx16g \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -Xlog:gc*:file=/var/log/app/gc.log:time,uptime,level,tags \
     -jar app.jar

# 分析 GC 日志
grep "Pause" /var/log/app/gc.log | tail -20

# 输出关键行:
# [2024-01-15T10:23:45.123+0800] GC Pause Young (Normal) 120ms
# [2024-01-15T10:23:52.456+0800] GC Pause Mixed 380ms
# [2024-01-15T10:24:01.789+0800] GC Pause Young (Concurrent Start) 520ms  <-- 长停顿

长停顿主要出现在 Young GC 和 Mixed GC 阶段。进一步用 jstat 观察堆内存分布:

jstat -gcutil $(pgrep -f app.jar) 5s

# 输出:
#  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
#  0.00  35.20  65.80  45.30  92.10  87.50    125     8.520     0    0.000    8.520
```

老年代(O)占用率 45%,元空间(M)占用率 92%,元空间接近满,触发频繁 Full GC 风险。

## 优化方案

**第一步:切换鲲鹏优化的 JDK 版本**

```bash
# 下载毕昇 JDK(BiSheng JDK)for ARM
wget https://mirrors.huaweicloud.com/bisheng/jdk/17/bisheng-jdk-17-linux-aarch64.tar.gz
tar xzf bisheng-jdk-17-linux-aarch64.tar.gz -C /usr/lib/jvm/

# 设置环境变量
export JAVA_HOME=/usr/lib/jvm/bisheng-jdk-17
export PATH=$JAVA_HOME/bin:$PATH

# 验证
java -version
# openjdk version "17.0.9" 2023-10-17
# OpenJDK Runtime Environment BiSheng (build 17.0.9+9)

第二步:调整 G1 GC 参数适配鲲鹏架构

# 启动参数优化
java -Xms16g -Xmx16g \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -XX:G1HeapRegionSize=32m \
     -XX:+UseNUMA \
     -XX:+UseLargePages \
     -XX:ParallelGCThreads=16 \
     -XX:ConcGCThreads=8 \
     -Xlog:gc*:file=/var/log/app/gc.log:time,uptime,level,tags \
     -jar app.jar

关键参数说明:

  • G1HeapRegionSize=32m:匹配鲲鹏 64MB L3 缓存,减少跨 region 访问
  • UseNUMA:让 G1 感知 NUMA 拓扑,优先分配本地内存
  • ParallelGCThreads=16:设为单 NUMA 节点核数,避免跨节点调度
  • ConcGCThreads=8:并发标记线程数减半,降低 CPU 竞争

第三步:启用大页减少 TLB miss

# 系统层面配置大页
echo 8192 > /proc/sys/vm/nr_hugepages

# JVM 启动参数添加
-XX:+UseLargePages \
-XX:LargePageSizeInBytes=2m

效果验证

使用 JMH 压测并采集 GC 指标:

指标优化前(OpenJDK 17)优化后(毕昇 JDK + 调优)
平均 GC 停顿95ms28ms
P99 GC 停顿520ms45ms
Young GC 频率12 次/分钟8 次/分钟
吞吐量下降3.2%0.8%

小结

鲲鹏上 Java GC 停顿大的根因是通用 OpenJDK 的 JIT 编译器和 G1 策略未针对 ARM 微架构优化。核心优化点:切换毕昇 JDK(针对鲲鹏优化)、启用 UseNUMA 感知拓扑、调整 G1HeapRegionSize 匹配缓存、开启大页。建议用 jstat -gcutil 监控元空间占用,用 GC 日志分析停顿分布,避免 Full GC 触发。

收藏举报
Level 1
0
帖子
0
粉丝
0
获赞