高并发压测与性能优化实战

目录

[① 导读卡片](#① 导读卡片)

[② 背景与目标](#② 背景与目标)

为什么学?

学完能怎样?

[③ 核心概念与原理](#③ 核心概念与原理)

[3.1 两个核心工具](#3.1 两个核心工具)

[3.2 关键性能指标](#3.2 关键性能指标)

[3.3 压测的黄金法则](#3.3 压测的黄金法则)

[④ 核心详解:完整调优流程](#④ 核心详解:完整调优流程)

[4.1 第一步:Druid 监控采集线上数据](#4.1 第一步:Druid 监控采集线上数据)

[4.2 第二步:JMeter 压测](#4.2 第二步:JMeter 压测)

[4.3 第三步:诊断与优化](#4.3 第三步:诊断与优化)

[4.4 第四步:再次压测验证](#4.4 第四步:再次压测验证)

[⑤ 典型应用案例](#⑤ 典型应用案例)

[5.1 案例:巡检提交系统性能优化](#5.1 案例:巡检提交系统性能优化)

[5.2 数据溯源口诀](#5.2 数据溯源口诀)

[⑥ 常见坑与最佳实践](#⑥ 常见坑与最佳实践)

[6.1 易错点清单](#6.1 易错点清单)

[6.2 面试话术](#6.2 面试话术)

[6.3 最佳实践清单](#6.3 最佳实践清单)

[⑦ 总结与学习路线图](#⑦ 总结与学习路线图)

核心要点速览

核心数字体系

自检清单

下一步学习

① 导读卡片

🧩 一句话读懂 :用 Druid SQL 监控看线上真实数据,用 JMeter 压测做优化前后对比,构建一套从"发现问题 → 定位瓶颈 → 验证优化"的完整性能调优打法 🎯 适合人群 :Java 后端开发者、性能调优入门/进阶者、面试准备者 📊 难度等级 :★★★☆☆(中等) ⏱ 阅读时长 :约 12 分钟 💡 前置知识:Spring Boot + Druid 基础、MySQL 基本操作


② 背景与目标

为什么学?

很多开发者做性能优化会陷入两个误区:

  1. 凭感觉优化------"我觉得这里慢",改完没有数据对比

  2. 只会背概念------知道连接池、索引、批量操作,但面试官问"你们怎么测的"就卡住了

真正的性能优化不是拍脑袋猜,而是基于数据的

复制代码
监控线上数据 → 发现瓶颈 → 制定方案 → 压测验证 → 上线观察

学完能怎样?

  • 掌握 Druid SQL 监控的线上数据采集方法

  • 能用 JMeter 做压测并正确解读结果

  • 能说清楚性能指标的含义(TPS、P50、P99、超时率)

  • 面试时能讲出一套完整的优化案例,有数据有对比有逻辑


③ 核心概念与原理

3.1 两个核心工具

工具 用途 面试官问"怎么测的"
Druid SQL 监控 线上真实数据,统计每条 SQL 的执行时间、调用次数、慢查询比例 "线上用 Druid 的 stat filter 监控的"
JMeter 压测 优化前后对比验证,模拟高并发 "上线前用 JMeter 压测对比的"

核心打法:Druid 负责线上真实数据,JMeter 负责优化前后对比验证。缺一不可。

3.2 关键性能指标

指标 全称 含义 怎么用
TPS Transactions Per Second 每秒完成的事务数 衡量系统吞吐量
P50 50th Percentile 50% 的请求在此时间内完成 代表大多数用户体验
P99 99th Percentile 99% 的请求在此时间内完成 反映尾部延迟
超时率 Timeout Rate 超时请求占总请求比例 衡量系统稳定性
平均响应 Average Response Time 所有请求的平均处理时间 宏观性能指标

3.3 压测的黄金法则

压测并发量 = 日常峰值 × 1.5~2 倍

不是随便设个并发数往上打,而是基于线上实际数据来设:

  • 先看 Druid 监控确认日常峰值 TPS

  • 压测在这个基础上 ×1.5~2,验证系统冗余

  • 如果这个量都扛不住,说明正式上线不安全


④ 核心详解:完整调优流程

4.1 第一步:Druid 监控采集线上数据

配置开启:

复制代码
spring:
  datasource:
    druid:
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
        login-username: admin
        login-password: admin123
      filter:
        stat:
          enabled: true
          log-slow-sql: true
          slow-sql-millis: 200   # 超过 200ms 的 SQL 记录为慢查询

打开 http://localhost:8080/druid/sql.html 可以看:

  • SQL 执行统计:每个 SQL 的执行次数、总耗时、平均耗时

  • 连接池状态:活跃连接数、等待数、创建数

  • URI 监控:哪个接口最慢、调用量最大

从 Druid 能获取的数字:

数据 获取方式
日常峰值 TPS 高峰时段 SQL 执行次数 ÷ 时间窗口
单事务耗时 Druid SQL 监控的平均耗时统计
慢查询 SQL Druid 慢查询日志
活跃连接数 连接池监控页

4.2 第二步:JMeter 压测

压测前的准备工作:

  1. 确认压测环境和线上环境配置一致(或按比例缩容)

  2. 设定超时时间(一般 3 秒)

  3. 压测持续 5~10 分钟(排除瞬时波动)

  4. 记录优化前的全部指标

JMeter 核心配置:

参数 设置依据
线程数(并发) 日常峰值 TPS × 1.5~2
Ramp-Up 时间 5~10 秒(逐步加压,避免瞬间打崩)
持续时间 300~600 秒
超时 3000ms
监听器 聚合报告、TPS 曲线、错误率

4.3 第三步:诊断与优化

常见性能瓶颈与对应方案:

瓶颈 表现 Druid 特征 优化方案
SQL 无索引 单条 SQL 耗时 > 200ms 慢查询日志频繁 分析执行计划,补索引
连接池太小 大量获取连接超时 activeCount=最大值,waitCount 高 适当调大 maxActive
连接池太大 TPS 不上反降 无异常但性能差 减少连接数到拐点
单条 INSERT 过多 网络往返多 执行次数高但每单耗时低 开启批量操作
事务内操作过多 连接释放慢 事务时长 > 100ms 缩短事务范围

4.4 第四步:再次压测验证

优化后在同条件下重新压测,对比两轮数据:

指标 优化前 优化后 改善幅度
平均响应 3 秒 500ms -83%
超时率 40% <1% -98%
单事务耗时 50ms <20ms -60%

注意:一定要同条件对比------同样并发数、同样时长、同样硬件。否则对比无效。


⑤ 典型应用案例

5.1 案例:巡检提交系统性能优化

📋 需求描述:2000 个猪舍,早高峰 6 分钟窗口集中提交巡检结果。优化前接口性能差,超时率高。

📊 优化前数据(Druid 监控):

指标 来源
日常峰值 TPS ~200 Druid 监控高峰期统计
单事务耗时 50ms Druid SQL 平均耗时
连接池 maxActive=20 配置值
慢查询 Druid 监控

📊 优化前压测数据(JMeter,300 并发):

指标
平均响应 3 秒
超时率 40%
P50 1.2 秒
P99 10+ 秒

🔍 诊断: 单事务耗时 50ms 偏高,原因是 7 条巡检明细分 7 次单条 INSERT------网络往返 7 次,占了绝大部分时间。连接池 20 个连接也有点紧。

⚡ 优化方案:

  1. 批量 INSERT :开启 rewriteBatchedStatements=true,7 条 INSERT 合并为 1 条

  2. 调整连接池:maxActive 从 20 调到 25(4核8G 服务器)

  3. 补索引:条件查询字段加索引,减少锁等待

复制代码
# 连接池+JDBC 配置优化
spring:
  datasource:
    druid:
      max-active: 25
      min-idle: 10
      max-wait: 3000
      url: jdbc:mysql://localhost:3306/mes_db?rewriteBatchedStatements=true

📊 优化后压测数据(同条件重跑):

指标 优化前 优化后
平均响应 3 秒 500ms
超时率 40% <1%
单事务耗时 50ms <20ms
TPS ~200 >500

5.2 数据溯源口诀

复制代码
Druid → 线上真实数据(TPS、单事务耗时)
JMeter → 优化前后对比验证
压测并发 = 日常峰值 × 1.5~2

面试官问任何数字,先说来源再说值:"这个数是从 Druid 监控/JMeter 压测得来的",顺序不能反。


⑥ 常见坑与最佳实践

6.1 易错点清单

# 坑点 现象 ✅ 避坑方案
1 优化后和优化前压测条件不一致 对比数据无效 同一台机器、同并发数、同时长
2 只压测不线上验证 压力少了看起来好,上线又崩 压测OK后,上线持续监控一周
3 并发连接数 = TPS 的误解 担心压测 300 TPS 会打崩 MySQL 300 TPS 对 MySQL 很轻松,不是问题
4 只调连接池不优化 SQL 连接池放大了但慢SQL还在 先优化 SQL,再调连接池
5 凭感觉"我觉得这里慢" 改了不该改的地方 基于 Druid 监控数据做决策

6.2 面试话术

Q:你们 200 TPS 怎么算的?
Druid SQL 监控页面上看高峰期 SQL 执行次数,除以时间窗口算的。比如高峰期 6 分钟内 SQL 执行次数统计后换算成每秒大约 200 次。
Q:为什么压测要打 300~400 TPS,不是 200?
压测一般按日常峰值的 1.5~2 倍做。日常 200,压测打到 300~400,是验证系统在有突发流量时能不能扛住。如果这个量都扛不住,正式上线高峰期有个小波动就崩了。
Q:把单事务耗时从 50ms 降到 20ms 是怎么做到的?
核心优化是批量 INSERT。原来 7 条明细分 7 次 INSERT,网络往返就占了大部分时间。开启 rewriteBatchedStatements=true 后合并成一条多值 INSERT,网络往返从 7 次降到 1 次,加上连接池和索引的小幅调整,整体耗时就降下来了。
Q:300 并发打进去,数据库扛得住吗?
300~400 TPS 对 MySQL 来说不算高,单机轻松能扛。MySQL 的 max_connections 是最大连接数(默认 151),但一个连接可以串行处理多个事务。真正扛不住的不是 TPS 高,而是慢 SQL 卡住连接、锁竞争或者连接池耗尽。我们压测发现瓶颈恰恰是配置问题,不是数据库本身。
Q:P50 和 P99 是什么?
P50 是中位数------50% 的请求在这个时间内完成,代表大多数用户的体验。P99 是 99% 的请求在此时间内完成,反映尾部延迟------不管服务器多快,总有些请求因为各种原因(GC、网络抖动、排队)特别慢,P99 就是看这个最慢的 1% 能不能接受。优化前 P99 超过 10 秒,说明有一批用户体验极差。

6.3 最佳实践清单

  • 先监控,后优化:没有 Druid 数据不出方案

  • 压测条件一致:同一硬件、同一并发、同一时长

  • 逐步调整:连接池每次调 5~10,反复压测找到拐点

  • 上线后持续观察:优化后至少监控一周,确认线上表现

  • 不说来源的数字都是废话:"大约 200 TPS" = "从 Druid 监控看到的 200 TPS"


⑦ 总结与学习路线图

核心要点速览

维度 要点 一句话记住
工具 Druid + JMeter Druid 看线上,JMeter 做对比
压测并发 峰值 × 1.5~2 验证冗余,不是打崩
优化顺序 SQL → 连接池 → 架构 先解决慢查询,再调连接池
数据来源 先说工具再说值 "Druid 监控显示......"

核心数字体系

数字 定位 来源
~200 TPS 日常业务峰值 Druid SQL 监控
300~400 TPS 压测并发量(1.5~2 倍峰值) JMeter
50ms 优化前单事务耗时 Druid 监控
3 秒 → 500ms 优化前后平均响应 JMeter 对比
40% → <1% 优化前后超时率 JMeter 对比

自检清单

  • 我能说清楚 Druid 和 JMeter 各自负责什么
  • 我知道压测并发量怎么确定(1.5~2 倍峰值)
  • 我能讲一个完整的优化案例(发现问题 → 定位 → 优化 → 验证)
  • 我知道 P50、P99、TPS 的含义和用途

下一步学习

复制代码
阶段一(基础):掌握 Druid 配置 + JMeter 基本用法 → 完成本文
阶段二(进阶):MySQL 执行计划分析、索引优化、连接池参数深入调优
阶段三(高阶):读写分离、分库分表、缓存优化、全链路压测