SpringBoot 性能优化实战

应用能跑起来,只是第一步。跑得快、跑得稳,才是生产环境的要求。

很多 SpringBoot 项目在上线初期一切正常,随着数据量增长、用户量增加,慢慢就变慢了。这时候再去优化,往往要花好几倍的时间。

性能优化最好的时机,是写代码的时候。

这篇文章从实际项目出发,总结了一套 SpringBoot 性能优化的"套路",按照见效快慢排序,先搞最容易出效果的。

一、优化优先级

性能优化不是瞎搞,要有优先级:

优化方向 预期效果
数据库(索引、SQL、连接池) 提升最大,最常见瓶颈
缓存(Redis、本地缓存) 减少重复计算
接口逻辑 减少不必要操作
容器线程池 提升并发能力
JVM 参数 减少 GC 停顿

记住:80% 的性能问题出在数据库,别一上来就去调 JVM。

二、数据库优化

数据库是绝大多数性能问题的根源,也是优化收益最大的地方。

2.1 先找到慢 SQL

不知道慢在哪里就没法优化。SpringBoot 提供了几种方式定位慢 SQL:

  • 开启 SQL 日志打印,观察执行时间

  • 使用 Druid 连接池的内置监控页面,可视化查看慢 SQL 排行

  • 在数据库层面开启慢查询日志

找到那些执行慢、调用频繁的 SQL,就是优化的突破口。

2.2 索引是重中之重

索引就像书的目录,没有索引就是从头翻到尾。

需要加索引的场景包括:WHERE 条件中的字段、ORDER BY 排序字段、JOIN 关联字段。但也需要注意,索引不是越多越好,因为索引会占用空间,还会降低写入速度。

常见的索引失效情况有:在索引列上使用函数、使用不等于运算、LIKE 以通配符开头等。

2.3 避免 N+1 查询

这是非常常见的问题:先查出一批数据,再循环逐条查询关联数据。

解决方案有两种:一是使用 JOIN 一次性查出所有关联数据,二是使用批量查询,一次性查出所有需要的关联数据,然后在内存中组装。

2.4 连接池配置要合理

SpringBoot 默认使用 HikariCP,这是目前性能最好的连接池。

连接数不是越大越好。每个连接都会占用内存和 CPU,连接过多反而会导致上下文切换频繁,性能下降。通常 10 到 20 个连接就足够了,具体可以根据压测结果调整。


三、缓存优化

缓存的核心思想:把经常读、不常变的数据存起来,下次直接从缓存拿。

3.1 本地缓存

本地缓存适合数据量小、不跨服务共享的场景,比如字典表、配置信息。

SpringBoot 内置了缓存抽象,只需要在方法上添加 @Cacheable 注解,返回值就会被自动缓存。配合 Caffeine 这种高性能本地缓存库,可以设置过期时间、最大数量等。

3.2 分布式缓存

Redis 是分布式缓存的首选,适合跨服务共享的数据,比如用户会话、热点业务数据。

使用缓存时需要注意几个经典问题:

  • 缓存穿透:查询不存在的数据,解决方案是缓存空值或使用布隆过滤器

  • 缓存雪崩:大量缓存同时失效,解决方案是给过期时间加上随机值

  • 缓存击穿:热点 Key 失效瞬间大量请求打到数据库,解决方案是使用互斥锁或设置热点数据永不过期


四、接口优化

4.1 按需返回字段

很多时候前端只需要几个字段,但接口把整个实体对象都返回了。按需返回可以减少网络传输量,也能降低数据库查询压力。

4.2 分页查询

列表接口一定要分页,不要一次性查询所有数据。数据量大了之后,一次性查询不仅慢,还可能导致内存溢出。

4.3 非核心逻辑异步化

发送邮件、记录操作日志、推送消息等非核心逻辑,可以放到异步线程池中执行,不让它们阻塞主流程。SpringBoot 的 @Async 注解可以轻松实现。

4.4 避免大事务

事务中不要包含远程调用、大量循环操作等耗时逻辑。事务持有锁的时间越长,并发越差。应该只把真正需要保证一致性的操作放在事务中。


五、容器与线程池优化

5.1 Tomcat 线程池

SpringBoot 内嵌的 Tomcat 默认线程数不算大,可以根据服务器配置适当调整。最大工作线程数建议设置在 200 左右,太小了并发能力不足,太大了反而增加上下文切换开销。

5.2 业务线程池

业务中的异步任务应该有独立的线程池,避免占用 Tomcat 的工作线程。线程池的核心参数需要根据任务类型来定:IO 密集型任务可以设置大一点的线程数,CPU 密集型任务线程数不宜超过 CPU 核心数。


六、JVM 参数优化

JVM 参数优化排在最后,因为大多数应用还不到这一步。

最基础的配置是设置堆内存大小:-Xms-Xmx 设置为相同的值,避免运行中扩容。垃圾回收器推荐使用 G1,设置合理的停顿目标即可。

对于容器化部署,堆内存需要根据容器内存限制来设置,通常设为容器内存的 70% 左右,留一些给系统和其它进程。


七、排查工具推荐

当应用变慢了,需要工具来定位问题:

Arthas 是阿里开源的 Java 诊断工具,可以在线看线程状态、方法调用耗时、入参出参,非常强大。

压测工具 方面,ab(Apache Bench)适合简单快速的压测,JMeter 功能更全面,支持复杂的测试场景。

总结

性能优化是一套方法论,不是玄学:

阶段 做什么
写代码时 注意索引、分页、缓存、异步
测试时 压测、定位瓶颈
上线前 检查清单过一遍
出问题时 用工具定位,针对性优化

最后记住一句话:

过早优化是万恶之源,但不优化是更大的恶。优先搞定数据库和缓存,其他地方按需优化就好。

相关推荐
小强19888 分钟前
Java程序员必知的4种引用类型:强、软、弱、虚——彻底告别内存泄漏
后端
鱼人11 分钟前
Spring Boot启动过程中偷偷干了什么?手撕run方法源码
后端
长大198811 分钟前
MySQL + Redis + Caffeine:Java后端通用三级缓存架构实战
后端
乘风破浪酱5243612 分钟前
别再乱用Redisson分布式锁了!这可能是你见过最标准的教程(附完整代码)
后端
兔子零102419 分钟前
当 Codex 成为主力,软件工程的重心已经变了
前端·后端·架构
用户67570498850225 分钟前
别再死记硬背了!一文扒光 I/O 多路复用的底裤(Epoll/Select/Poll)
后端
牛奶29 分钟前
网关是怎么当"门卫"的?
前端·后端·负载均衡
悟空聊架构37 分钟前
100多G数据同步引发的MySQL集群“连环炸”,我是如何一步步恢复的? - 墨天轮
后端·架构
Hemy0839 分钟前
tauri + rust 创建初始项目
开发语言·后端·rust