SpringBoot性能优化的12个小技巧

前言

不知道你在SpringBoot项目中,有没有遇到过下面这样的代码:

@GetMapping("/orders") public List<Order> listOrders() {     return orderDao.findAll();  } 

一次性查询了所有的订单,全表扫描50万数据,导致接口查询性能很差,严重的时候可能会导致OOM问题。

问题定位

  • 未分页查询
  • 无缓存机制
  • 未启用批量处理

这次事故让我明白:性能优化必须贯穿开发全流程

今天这篇文章,跟大家一起聊聊SpringBoot优化的12招,希望对你会有所帮助。

SpringBoot性能优化的12个小技巧

SpringBoot性能优化的12个小技巧

第1招:连接池参数调优

问题场景
默认配置导致连接池资源浪费,高并发时出现连接等待

错误配置

spring:   datasource:     hikari:       maximum-pool-size: 1000        connection-timeout: 30000 

数据库连接池的最大连接数,盲目设置过大,连接超时时间设置过长。

优化方案

spring:   datasource:     hikari:       maximum-pool-size: ${CPU核心数*2} # 动态调整       minimum-idle: 5       connection-timeout: 3000 # 3秒超时       max-lifetime: 1800000 # 30分钟       idle-timeout: 600000 # 10分钟空闲释放 

数据库连接池的最大连接数,改成根据CPU核心数动态调整。

将连接超时时间由30000,改成3000。

第2招:JVM内存优化

问题场景
频繁Full GC导致服务卡顿

我们需要优化JVM参数。

启动参数优化

java -jar -Xms4g -Xmx4g  -XX:NewRatio=1  -XX:+UseG1GC  -XX:MaxGCPauseMillis=200  -XX:InitiatingHeapOccupancyPercent=35 -XX:+AlwaysPreTouch 

最大堆内存和初始堆内存都设置成了4G。

-XX:NewRatio=1,设置新生代和老年代各占一半。

垃圾收集器配置的是G1。

垃圾回收的最大停顿时间为200毫秒。

第3招:关闭无用组件

问题场景
自动装配加载不需要的Bean

优化方案

@SpringBootApplication(exclude = {     DataSourceAutoConfiguration.class,     SecurityAutoConfiguration.class }) public class Application {     public static void main(String[] args) {         SpringApplication.run(Application.class, args);     } } 

如果有些功能暂时用不到,可以先排除一下。

在SpringBoot项目启动的时候,排除了DataSourceAutoConfiguration和SecurityAutoConfiguration配置类的自动装载。

第4招:响应压缩配置

问题场景
接口返回JSON数据体积过大

优化方案

server:   compression:     enabled: true     mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/json     min-response-size: 1024 

配置开启响应的压缩。

第5招:请求参数校验

问题场景
恶意请求导致资源耗尽

防御代码

@GetMapping("/products") public PageResult<Product> list(     @RequestParam @Max(value=100, message="页大小不能超过100") int pageSize,     @RequestParam @Min(1) int pageNum) {     //... } 

在接口中做好参数校验,可以拦截很多恶意请求。

第6招:异步处理机制

问题场景
同步处理导致线程阻塞

优化方案

@Async("taskExecutor") public CompletableFuture<List<Order>> asyncProcess() {     return CompletableFuture.completedFuture(heavyProcess()); }  @Bean("taskExecutor") public Executor taskExecutor() {     ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();     executor.setCorePoolSize(5);     executor.setMaxPoolSize(10);     executor.setQueueCapacity(500);     return executor; } 

在有些业务逻辑中,使用异步处理性能可能会更好。

第7招:使用缓存

使用缓存可以提升效率。

缓存架构

SpringBoot性能优化的12个小技巧

代码实现

@Cacheable(cacheNames = "products", key = "#id",             cacheManager = "caffeineCacheManager") public Product getDetail(Long id) {     return productDao.getById(id); } 

这里使用了内存缓存。

第8招:批量操作优化

问题场景
逐条插入导致性能低下

优化方案

@Transactional public void batchInsert(List<Product> products) {     jdbcTemplate.batchUpdate(         "INSERT INTO product(name,price) VALUES(?,?)",         products,         500, // 每批数量         (ps, product) -> {             ps.setString(1, product.getName());             ps.setBigDecimal(2, product.getPrice());         }); } 

每500条数据插入一次数据库。

第9招:索引深度优化

问题场景
慢查询日志频繁出现全表扫描,SQL执行时间波动大

错误案例

-- 商品表结构 CREATE TABLE products (     id BIGINT PRIMARY KEY,     name VARCHAR(200),     category VARCHAR(50),     price DECIMAL(10,2),     create_time DATETIME );  -- 低效查询 SELECT * FROM products  WHERE category = '手机'  AND price > 5000  ORDER BY create_time DESC; 

问题分析

SpringBoot性能优化的12个小技巧

优化方案一:联合索引设计

索引创建

下面创建了一个分类ID,单价和时间的联合索引:

ALTER TABLE products  ADD INDEX idx_category_price_create  (category, price, create_time); 

优化方案二:覆盖索引优化

查询改造

只查询索引包含字段:

SELECT id, category, price, create_time  FROM products  WHERE category = '手机'  AND price > 5000  ORDER BY create_time DESC; 

这里使用了覆盖索引。

优化方案三:索引失效预防

常见失效场景

SpringBoot性能优化的12个小技巧

案例修复

错误写法:

SELECT * FROM products  WHERE DATE(create_time) = '2023-01-01'; 

正确写法:

SELECT * FROM products  WHERE create_time BETWEEN '2023-01-01 00:00:00'  AND '2023-01-01 23:59:59'; 

查询时间范围,这里使用了BETWEEN AND关键字,代替了等于号。

优化方案四:索引监控分析

诊断命令

查看索引使用情况:

SELECT      index_name,     rows_read,     rows_selected  FROM      sys.schema_index_statistics  WHERE      table_name = 'products'; 

分析索引效率:

EXPLAIN FORMAT=JSON  SELECT ...; 

索引优化黄金三原则

  1. 最左前缀原则:联合索引的第一个字段必须出现在查询条件中
  2. 短索引原则:整型字段优先,字符串字段使用前缀索引
  3. 适度索引原则:单个表索引数量不超过5个,总索引长度不超过表数据量30%

DBA工具箱

  • 索引分析脚本
  • 执行计划可视化工具
  • 索引碎片检测工具

第10招:自定义线程池

问题场景
默认线程池导致资源竞争

优化方案

@Bean("customPool") public Executor customThreadPool() {     return new ThreadPoolExecutor(         10, // 核心线程         50, // 最大线程         60, TimeUnit.SECONDS,         new LinkedBlockingQueue<>(1000),         new CustomThreadFactory(),         new ThreadPoolExecutor.CallerRunsPolicy()); } 

在高并发业务场景中,使用Executors类创建默认的线程池,可能会导致OOM问题。

因此,我们需要自定义线程池。

第11招:熔断限流策略

问题场景
突发流量导致服务雪崩

解决方案

// 使用Sentinel实现接口限流 @SentinelResource(value = "orderQuery",                    blockHandler = "handleBlock",                   fallback = "handleFallback") @GetMapping("/orders/{id}") public Order getOrder(@PathVariable Long id) {     return orderService.getById(id); }  // 限流处理 public Order handleBlock(Long id, BlockException ex) {     throw new RuntimeException("服务繁忙,请稍后重试"); }  // 降级处理 public Order handleFallback(Long id, Throwable t) {     return Order.getDefaultOrder(); } 

为了解决重复流量导致服务雪崩的问题,我们需要增加接口熔断、限流和降级处理。

第12招:全链路监控体系

问题场景
线上问题定位困难,缺乏数据支撑

我们需要增加项目全链路的监控。

监控方案

# SpringBoot配置 management:   endpoints:     web:       exposure:         include: "*"   metrics:     export:       prometheus:         enabled: true 

这里使用了prometheus监控。

监控架构

SpringBoot性能优化的12个小技巧

核心监控指标

SpringBoot性能优化的12个小技巧

总结

SpringBoot性能优化检查清单

  • 连接池参数按业务调整
  • JVM参数经过压测验证
  • 所有查询走缓存机制
  • 批量操作替代逐条处理
  • 线程池按场景定制
  • 全链路监控覆盖

SpringBoot性能优化的12个小技巧

三条黄金法则

  1. 预防性优化:编码时考虑性能影响
  2. 数据驱动:用监控指标指导优化方向
  3. 持续迭代:性能优化是持续过程

性能工具包

  • Arthas在线诊断
  • JProfiler性能分析
  • Prometheus监控体系

(看着监控大屏上平稳的QPS曲线,我知道今晚可以睡个好觉了...)

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下我的同名公众号:苏三说技术,我的所有文章都会在公众号上首发,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

关注公众号:【苏三说技术】,在公众号中回复:进大厂,可以免费获取我最近整理的10万字的面试宝典,好多小伙伴靠这个宝典拿到了多家大厂的offer。

本文收录于:www.susan.net.cn

发表评论

评论已关闭。

相关文章