Spring Boot 应用性能调优
2025-10-31 17:28:21 0 举报
AI智能生成
分别从日志、数据库、缓存、cpu、内存、gc六个纬度对 Spring Boot 应用性能调优
作者其他创作
大纲/内容
日志(优先级 ★☆☆☆☆,上线后发现才管)
目标
日志不成为 I/O 瓶颈,且保留足够排查信息
信号
压测时磁盘 I/O util 飙高,logback 线程占 CPU 10 %+
日志文件一秒滚动一次,体积几百 MB
调优
关闭控制台输出(console appender)
生产只保留 ≥WARN 的 root,业务 logger 单独开 INFO 并加 <totalSizeCap>、<maxFileSize> 限流
异步 Appender(AsyncAppender 或 logstash-logback-encoder 的 AsyncDisruptorAppender)(QPS>3k 时提升 5~15 %)
关闭 hibernate SQL 日志、Spring Boot 的 ConditionEvaluationReport 等调试日志
数据库(优先级 ★★★★☆,80 % 性能问题根源)
目标
把 N+1、慢 SQL、大事务、连接池抖动的耗时压到 50 ms 以内
信号
压测 TPS 随并发线性增长,但 RT 在 200 ms 以上
数据库 CPU 60 %+,或连接池频繁等待
调优
连接池调优(HikariCP)
maximum-pool-size = (core_count * 2) + effective_spindle_count,默认 10 太小
minimum-idle = max-size * 0.3~0.5,idle-timeout=60s,max-lifetime=30min
索引与执行计划
spring.jpa.show-sql=false,开 datasource-proxy + p6spy 聚合 >100 ms SQL;
EXPLAIN 看是否走索引,避免 filesort、临时表
业务层减负
只查需要的列,用 JOIN/FETCH 一次拿完,杜绝 N+1;
分页用 WHERE id > #{lastId} LIMIT #{size} 替代 OFFSET 大分页
事务瘦身
只读查询加 @Transactional(readOnly = true),单表更新去掉 @Transactional 嵌套;
把批处理拆成 1 k 条/次,带 ORDER BY PRIMARY KEY 游标,防间隙锁飙升
缓存(优先级 ★★★☆☆,挡 10 倍流量)
目标
让 80 % 读请求落在内存,缓存命中率 ≥90 %
信号
慢 SQL 已经优化,但 RT 仍 100 ms+,数据库 QPS 2 k+
调优
本地缓存(Caffeine)
spring.cache.type=caffeine,maximumSize=10k,expireAfterWrite=5m;
对“类目、字典”等极少变更数据可设 1 h
分布式缓存(Redis/Memcached)
热 key 大 value(>1 KB)用 gzip 压缩;
批量接口用 mget、pipeline 减少 RTT;
缓存空对象防穿透,布隆过滤器防击穿
缓存一致性
写后删除优于双写;
采用“MQ + 延时双删”或 Canal 订阅 binlog 异步删,降低延迟
CPU(优先级 ★★☆☆☆,先定位再优化)
目标
把 CPU 压到 60 % 以内,留 40 % 缓冲
信号
压测时 4C8G 机器 CPU 90 %+,但数据库、缓存 RT 很低
调优
火焰图定位热点
async-profiler 采样,查看是否 JSON 序列化、反射、正则、大循环
减少高开销操作
用 Jackson Afterburner、Gson 的 FieldNamingStrategy 缓存;
日志里拼接字符串改占位符;
正则预编译 static final Pattern
并行与异步
计算密集型用 ForkJoinPool.commonPool(),I/O 型自定义 ThreadPoolTaskExecutor;
WebFlux 场景用 Schedulers.parallel() 隔离
内存(优先级 ★★☆☆☆,防突发 FGC)
目标
GC 后老年代剩余 30 %+,堆外内存不泄露
信号
压测 10 min 后老年代 95 %,FGC 每 30 s 一次
调优
合理设堆
容器 4G → -Xms2g -Xmx2g,禁止抖动扩容;
大对象(>1 MB)直接进老年代,避免频繁 Young GC
对象生命周期
用完即清理:ThreadLocal.remove()、缓存淘汰、HttpClient 连接池复用
排查堆外
jcmd VM.native_memory summary,看 Arena / DirectByteBuffer 是否暴涨;
Netty 场景开启 -Dio.netty.maxDirectMemory=0 限制
GC(优先级 ★★☆☆☆,最后 5 % 的极致)
目标
YGC <50 ms,FGC 间隔 >30 min,TP99 无毛刺
信号
GC 日志出现 200 ms+ 的停顿,或 Allocation Failure 频繁
调优
选收集器
4C8G 以下:JDK8 用 ParNew+CMS,JDK11+ 用默认 G1;
8C16G 以上:换 ZGC(JDK17+)或 Shenandoah
G1 调优模板
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100
-XX:G1HeapRegionSize=16m
-XX:G1NewSizePercent=25
-XX:G1MaxNewSizePercent=35
-XX:+PrintGCDetails -Xloggc:/opt/logs/gc.log
关键指标
jstat -gc -t 1s 100 | awk '{print $14,$15}' 看 YGC/FGC 次数与耗时;
GC 后 EU <20 % 且 OU 稳定即可
0 条评论
下一页