ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MySQL线程池插件压测:单库TPS提升近1.9倍实测

MySQL线程池插件压测:单库TPS提升近1.9倍实测

简介:针对高并发下MySQL线程创建与销毁开销引发的性能瓶颈,这份PDF文档面向数据库管理员、后端开发与性能测试人员,系统梳理线程池插件的原理、配置及压测落地方案。内容涵盖线程池工作机制与my.cnf关键参数、测试环境网络拓扑和软硬件配置、测试数据准备与代码改造,以及基准、压力、稳定性和逐步加压负载等测试方法;并结合新增线程池前后四库、单库负载与稳定性测试章节,给出QPS、TPS、响应时间、资源利用率和瓶颈定位的对比思路,便于读者按目录复现测试流程、评估优化收益。资源包共1个PDF文件,约3.26MB,结构完整、目录清晰。已有446人学习下载,适合需要开展MySQL高并发优化与性能压测的初中级技术人员参考。

1. 先把线程池的价值说清楚:高并发抖动不一定要靠加机器解决

现网数据库一到高峰期就开始抖,很多人的第一反应是加内存、加从库、换存储。这份 MySQL 线程池插件性能压测方案给出的路子更省:不动架构、不加节点,只把连接处理模型从“一连接一线程”换成线程池,先量出它到底能换来多少吞吐。有个反直觉的现象值得先说:插件装上去,80 线程压测时四库 TPS 只从 129871 涨到 171907;真正拉开差距是在单库、400 线程那一档,TPS 从 131676 冲到 250274,接近 1.9 倍。也就是说,线程池不是“装上就快”的玄学开关,它的收益跟并发档位强绑定。这套测试方案适合两类人:一类是要交一份完整数据库优化或性能压测课设、毕设的人,另一类是手上真有一台高并发 MySQL、需要拿数据说服团队上线插件的人。

2. 测试目标与环境基线:48 核 755G 单实例与四条硬指标

压测方案最先要落死的不是脚本,是“什么叫做通过”。指标含糊,后面所有 TPS 数字都失去意义——这也是我做性能方案时踩过的第一个坑:早期版本的验收条件只写了“性能有明显提升”,结果评审会上没人认账,翻来覆去重跑了三轮。所以这份方案把验收条件前置成四条可量化红线,再倒推环境配置和加压节奏。

2.1 四条验收红线:CPU 70%、I/O wait 30%、带宽 70%、成功率 99.99%

被测系统在运行过程中,CPU 与内存的平均使用率不高于 70%,系统 I/O wait 不高于 30%,网络带宽不超过 70%,处理成功率不低于 99.99%,90% 响应时间在 100ms 以内,且无系统告警、无内存溢出。这五条是“与”的关系,任何一条破了,当前这一档并发就不算通过,加压立即停止并转入定位。

把 CPU 卡在 70% 而不是 90%,是留出突发余量:压测是匀速的理想流量,现网是带毛刺的,70% 对应到现网大概就是 85% 左右的峰值水位。I/O wait 卡 30% 是因为这次被测的是一张宽表查询,一旦 I/O 打满,TPS 曲线会突然断崖,那时候的“最优容量”其实是磁盘的容量,不是数据库的容量。

提示:四条红线要在压测脚本跑第一轮之前就写进方案文档并经评审确认,中途改指标等于改考卷。

测试目标分三层:验证性(具体并发下系统的最大处理能力)、探测性(接口与整条链路的压力承受值)、调优性(发现瓶颈在哪)。三层目标对应后面完全不同的用例组织方式,验证性靠阶梯加压找拐点,探测性靠单点高压看崩溃边界,调优性靠监控数据回溯。

2.2 环境基线:一台数据库节点加四台负载机的拓扑与配置

压测环境的原则是“别让压测机先累死”。这次配置是一台数据库节点配四台负载机,规格全部对齐,避免出现施压端 CPU 先满、被测端还在闲着的假瓶颈。

角色内网地址(已脱敏)配置数量说明
MySQL 数据库节点10.x.x.548 核 / 755G 内存1被测实例,四套库同实例
负载机10.x.x.1 ~ 10.x.x.448 核 / 755G 内存4JMeter 施压,分布式压测
监控复用数据库节点——zabbix agent + 命令行采集

四台负载机的意义不只是“压力更大”,更重要的是把施压端自身的开销摊开。单台机器跑 400 线程的 JMeter,光线程切换和结果写盘就能吃掉可观 CPU,聚合报告里的响应时间会被施压端污染。四台分摊后,每台 100 线程,施压端 CPU 稳定在 30% 以下,测出来的数才干净。

四套库放在同一个实例上,是这次方案里一个刻意的设计:既能测“四个库同时被压”的混合场景,也能测“只压单库”的纯净场景。两种场景的差值,正好反映多库之间抢 buffer pool、抢磁盘队列的损耗。这也是后面用例矩阵分四组的原因。

2.3 测试数据准备:四张表的量级与参数化策略

基础数据量按现网缩比设定:client_app 20w 行、app_ability 30w 行、ability_attr 120w 行、conf_attr 1w 行。ability_attr 是主压表,120w 行的量级既能压出真实的索引深度,又不至于让单轮压测的数据准备时间失控。

请求体大小按现网最大请求体改造,这一点很容易被忽略。如果压测请求体比现网小一半,网络带宽和序列化开销都被低估,等到上线才发现带宽先到 70%,前面的 TPS 结论全部作废。参数化数据量按“并发数 × 并发时长”倒推:峰值 400 线程跑 300 秒,至少要准备 400 × 300 × 1.2 量级的参数组合,保证整个过程中参数不重复回绕。

被压的核心 SQL 是一条带双条件的主键类查询:

-- 被测查询:按主键与属性编码定位单行,避免全表扫描干扰结论 SELECT pkid, attrcode, attrname, attrvalue, date_format(create_time, '%Y-%m-%d %H:%i:%s') AS create_time, date_format(update_time, '%Y-%m-%d %H:%i:%s') AS update_time FROM ability_attr WHERE pkid = ? -- 参数化,由 JMeter 属性注入 AND attrcode = ?; -- 参数化,与 pkid 组合保证命中率

这条 SQL 有两个设计点。一是两个条件都参与参数化,且 pkid 走主键,保证每次查询都是索引命中单行,压的是连接与线程调度能力,不是优化器的选择能力。二是date_format保留在 SQL 里而不是挪到应用层,因为格式化本身就是 CPU 开销的一部分,去掉它会人为抬高 TPS,让线程池的收益被高估。

2.4 测试计划与人力分工:方案、部署、联调、执行、调优五段

计划按五个阶段推进,每段的产出物明确到人。方案制定与评审在同一天完成,输出终稿;环境部署由 DBA 负责,单实例和集群两套都要就绪;脚本联调确认参数化、断言、集合点都生效;执行阶段按用例矩阵逐条跑,边跑边收集数据;调优与回归是可选段,只有出现红线被击穿时才启动。

阶段主要任务责任角色产出
方案制定与评审定指标、定用例、定节奏测试负责人方案终稿
环境部署单实例与集群就绪、监控接入DBA可压测环境
脚本联调编写 jmx、调通参数化与断言测试工程师可用脚本
执行压测按矩阵逐条执行、采集数据测试工程师原始结果
调优回归定位瓶颈、改配置、复测DBA + 开发对比数据

人力上至少三个角色不能合并:施压脚本的编写者、数据库侧的调参者、结果的分析者。同一个人既写脚本又调库,很容易在“改了参数之后 TPS 涨了”这件事上归因错误——涨的可能只是这一轮压测机比较闲。这一点在后面避坑章节还会展开。

3. JMeter 脚本与阶梯加压:40 线程一档的节奏怎么定

脚本决定数据可不可信,节奏决定拐点找不找得到。这两件事经常被合并成“随便跑一下看看”,结果拿到的是一条没有拐点的直线,既说不清最优容量在哪,也证明不了线程池的收益区间。这一章把脚本结构和加压节奏拆开讲。

3.1 脚本结构:一个查询事务的元件拆解

单个 jmx 的结构分四层:线程组控制并发规模,CSV Data Set Config 提供参数,JDBC Request(或 HTTP 请求经应用层转发)发出查询,聚合报告与响应断言负责取证。线程组不开启调度器,靠外部命令分档启动,这样每一档的线程数是确定的,便于横向对比。

断言是这份脚本里最容易被省掉、也最不能省的部分。只配一个“响应码 200”的断言,等于默认所有慢查询都是成功的。方案里给每个事务加了两条断言:返回行数必须为 1,返回字段中的 attrcode 必须与入参一致。前者防主键查空,后者防参数错位。

<!-- 事务断言:返回行数与字段一致性双重校验,避免"假成功"抬高成功率 --> <ResponseAssertion guiClass="org.apache.jmeter.assertions.ResponseAssertion"> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <collectionProp name="Assertion.test_strings"> <stringProp name="1">1</stringProp> <!-- 期望返回 1 行 --> </collectionProp> <stringProp name="Assertion.custom_message">返回行数异常,疑似主键查空</stringProp> </ResponseAssertion>

参数化的来源用 CSV,每行一个 pkid 与 attrcode 组合,文件按并发数拆成多份分给四台负载机,避免四台机器读同一份文件时缓存互相干扰。CSV 的 Recycle on EOF 设为 false、Stop thread on EOF 设为 true,参数耗尽就停线程组——这个设置会让“参数不够”这件事以失败的形式暴露出来,而不是悄悄回绕把成功率拉回 100%。

3.2 阶梯加压逻辑:40 线程一档、每档稳定 5 分钟的判停规则

加压方式定为:从 40 个请求流开始,稳定运行 5 分钟;满足全部红线则再加 40 个请求流,继续稳定 5 分钟;依次递推。任一红线被击穿,立即停止加压,当前档位的前一档就是这一轮的“最优容量”。

为什么是 40 一档而不是 100 一档?档位太粗会跨过拐点。线程池的收益曲线不是线性的,在某个并发区间里 TPS 会有一个明显的跃升(这次的跃升点在单库从 80 线程往 400 线程走的过程中),档位太粗,你只会看到“最后那档没过”,却看不到跃升发生在哪。40 一档的代价是轮次多,用调度脚本串起来跑就行,人力成本其实不高。

每档稳定 5 分钟是第二个关键。压测刚开始的几十秒,buffer pool 还没热、连接还没建满、JIT 还没编译完,这段时间的 TPS 是偏低的。等 5 分钟再采样,曲线已经进入平台期,读出来的才是稳态值。

注意:阶梯加压过程中不要清空数据库缓存,也不要在两档之间重启实例。缓存状态一旦被重置,前后两档就不可比了。

判定通过之后还有一步“复压”:取刚才找到的最大能力请求量,重新发起一轮,持续 5 分钟。这一步是防突发,验证这个并发水平不是偶然冲上去的,而是可复现的。很多方案把这一步省了,答辩时被问“这个数稳定吗”就答不上来。

3.3 无界面执行与报告生成:三条命令跑完一轮压测

脚本在本地调通后,整个 apache-jmeter 目录上传到负载机,jmx 放进 bin 目录,用无界面模式执行。三条命令分别负责跑、存、出报告:

# 1. 无界面执行:-n 非 GUI,-t 指定脚本,-l 指定结果文件(jtl) ./jmeter -n -t ability_attr_400.jmx -l logs/run_400.jtl # 2. 由结果文件生成 HTML 报告,输出到指定目录(目录需不存在或为空) ./jmeter -g logs/run_400.jtl -o report/run_400 # 3. 分布式压测:四台负载机同时施压,-R 列出施压节点 ./jmeter -n -t ability_attr_400.jmx -R 10.x.x.1,10.x.x.2,10.x.x.3,10.x.x.4 \ -l logs/run_400_cluster.jtl

第一条命令里的-l文件是原始凭证,所有聚合数字都能从这里重算,务必保留,别只留 HTML。第二条命令要求输出目录事先不存在或为空,否则直接报错,这是新手最常撞的一堵墙。第三条的-R需要各节点先起 jmeter-server 并互通,分布式模式下每台机器的线程数要按总数均分,否则聚合报告里的并发数会翻倍。

报告生成后下载整个目录,打开 index.html 就能看到聚合报告、响应时间趋势、TPS 曲线三张图。方案里判定用的是聚合报告里的 90% 响应时间与错误率,趋势图只用来判断曲线是否平稳——趋势图上有明显爬升,说明这一档还没到稳态,5 分钟不够,得延长。

3.4 监控侧:zabbix、JVisualVM 与命令行三路取证

施压端只告诉你“多快”,监控端才告诉你“为什么这么快”或“为什么快不上去”。监控分三路:zabbix 负责 CPU、内存、网络的分钟级曲线,JVisualVM 挂到数据库节点看 JVM 侧的线程数与 GC(如果中间有 Java 应用层),命令行负责秒级抽样。

# 每 5 秒采样一次:CPU、上下文切换、磁盘 await、网络流量 # 输出追加到文件,压测结束后与 jtl 时间轴对齐分析 while true; do ts=$(date '+%H:%M:%S') cpu=$(top -bn1 | awk '/Cpu\(s\)/{print $2+$4}') cs=$(vmstat 1 2 | tail -1 | awk '{print $12}') io=$(iostat -x 1 2 | awk '/sda/{print $10}' | tail -1) echo "$ts cpu=${cpu}% cs=${cs} io_await=${io}" >> monitor/node_5s.log sleep 5 done

这段循环输出的是秒级快照,重点看三个量:CPU 使用率是否贴近 70% 红线、上下文切换次数(cs)是否随并发线性增长、磁盘 await 是否在 TPS 上涨时同步抬升。上下文切换如果涨得比 TPS 快很多,说明线程创建销毁的开销已经盖过了有效工作,这正是线程池该上场的信号;磁盘 await 突然抬升而 CPU 没满,说明瓶颈在 I/O,此时再调线程池参数基本无用。

三路数据最终要按时间轴对齐。做法是把 jtl 里的时间戳与 monitor 日志的时间戳统一到同一时区,取每档加压的第 3 分钟到第 5 分钟这个窗口做均值,避免起停阶段的毛刺污染结论。这一步多花二十分钟,但能省掉后面反复解释“为什么 CPU 曲线和 TPS 曲线对不上”的口舌。

4. 四组对照用例的落地:单库与四库、线程池前后的实测差异

对照实验的价值在于消变量。这次只改一个变量——线程池插件装或不装,其余环境、数据量、脚本、加压方式全部保持一致。为了同时回答“多库混合有没有额外损耗”这个问题,又把场景切成单库与四库两个维度,组成四组负载用例,外加一组稳定性用例。

4.1 用例矩阵:四组负载加一组稳定性怎么排

编号场景线程数时长关注点
A线程池前 · 四库80300s基线吞吐
B线程池前 · 单库80300s单库纯净基线
C线程池后 · 四库100300s混合场景收益
D线程池后 · 单库400300s单库上限与拐点
E线程池后 · 四库稳定性5212h长跑是否衰减

A 与 B 是基线,跑在线程池插件启用之前,用同样的四台负载机、同样的参数文件。C 与 D 是实验组,线程数按上一轮阶梯加压找到的最优容量取。E 只跑线程池后的版本,因为稳定性要验证的是“新配置能不能扛住长跑”,跑旧版本没有决策意义。

矩阵里有一处容易被质疑:A、B 的线程数(80)和 D 的线程数(400)差得太多,能对比吗?能,但要换个说法——比的是“各自的满载能力”,不是“同一并发下的表现”。想比同一并发,看 A 对 C(80 对 100)就够了;想看插件到底把天花板抬到多高,看 B 对 D。方案里这两组结论要分开写,混在一起讲就是给自己挖坑。

4.2 线程池插件安装与参数配置:thread_pool_size 与 stall_limit

插件的引入有两种路径:编译期启用,或运行期以插件方式加载。无论走哪条,配置都落在 my.cnf 里,关键是三个参数:连接处理模型、线程组数、以及线程等待新任务的最长毫秒数。

[mysqld] # 连接处理模型:从一连接一线程切换为线程池模型 thread_handling = pool-of-threads # 线程组数:决定并行处理请求的基本单元数量,按 CPU 核数与负载特征调 thread_pool_size = 32 # 线程在等待新任务时的最大停留毫秒数,超时后由线程池调度接管 thread_pool_stall_limit = 500

thread_pool_size是这套配置里最需要试的参数,不是越大越好。它本质上是“同时干活的分组数”,设得太小,请求排队;设得太大,组间切换开销上来,反而打不满 CPU。这次的对比测试里,32 组线程在单库 150 并发下跑出 TPS 240000、CPU 67%,把并发继续往上推,TPS 和 CPU 的涨幅都不明显了——这就是参数接近饱和的信号。

thread_pool_stall_limit控制的是“一个线程组卡住多久算卡住”。设得太小,正常的长查询会被判为停顿并触发额外线程,等于把线程池又退化成一线程一连接;设得太大,真卡住了也发现不了。500ms 是这套方案里的取值,实际调整要看 90% 响应时间的分布,如果绝大多数请求都在 10ms 内完成,这个值可以往下压到 200~300ms。

配置改完要重启实例生效,重启后先确认变量已经落地再开压:

-- 确认连接处理模型已切换为线程池 SHOW VARIABLES LIKE 'thread_handling'; -- 查看当前线程池的实际线程组数与运行状态 SHOW STATUS LIKE 'Threadpool%';

第一条必须返回pool-of-threads,返回one-thread-per-connection说明配置没生效,可能是 my.cnf 位置不对或被更高优先级的配置文件覆盖。第二条返回的一组计数器里,重点看空闲线程组数与等待队列长度,这两个数在压测过程中如果持续偏高,说明thread_pool_size还该往上加。

4.3 实测数据:129871 到 250274 的差距出现在哪一档

四组负载用例跑完,数字摆出来差异很明显:

用例线程数TPS90% 响应时间成功率CPU网络流量
A 线程池前 · 四库80129871≤1ms100%69%40.125MB
B 线程池前 · 单库80131676≤1ms100%68%41MB
C 线程池后 · 四库100171907≤1ms100%69%52.25MB
D 线程池后 · 单库400250274≤2ms100%67%75.125MB

先看四库场景:A 到 C,线程数从 80 提到 100,TPS 从 129871 涨到 171907,约 1.32 倍,CPU 都是 69% 左右,网络流量从 40.125MB 涨到 52.25MB。这个涨幅是“同水位下吞吐更高”,说明线程池减少了线程创建销毁的无效开销,把 CPU 真正用在了查询上。四库场景的天花板受限于实例共享资源竞争,收益被摊薄。

再看单库场景:B 到 D,TPS 从 131676 冲到 250274,接近 1.9 倍。这是这份方案里最有说服力的一组数,也是最容易被误读的一组——注意 D 的线程数是 400,不是 80。它的含义是“单库场景下,线程池把系统能承受的并发上限和对应的吞吐一起抬高了”,而不是“同样的 80 并发下快了 1.9 倍”。答辩时这句话说错,后面所有结论都要被追问。

还有一个细节值得写进报告:D 的 90% 响应时间从 ≤1ms 变成 ≤2ms。吞吐涨了,单请求延迟略微上浮,这是正常的——系统跑在更高的水位上,排队时间自然长一点。只要没破 100ms 的红线,这个 1ms 到 2ms 的变化属于可接受范围,但要主动写出来,别等人问。

4.4 稳定性与线程组数对比:12 小时与 32 组线程的两组补充验证

负载测试证明“能跑多快”,稳定性测试证明“能跑多久”。用例 E 用 52 线程持续压 12 小时,结果是 TPS 稳定在 95000 左右,90% 响应时间 ≤1ms,成功率 100%,CPU 60%,网络流量 27.5625MB,全程无告警、无内存溢出。

12 小时这个时长不是随手定的。短于 8 小时,很多慢性问题(连接句柄泄漏、慢 SQL 累积、临时表撑爆)根本来不及显形;超过 24 小时,测试窗口和人力成本又不好安排。12 小时刚好覆盖一个业务高峰到低谷的完整周期,性价比最高。跑的时候要盯的不是 TPS 均值,而是 TPS 的尾部——如果最后两小时的 TPS 比前两小时低 5% 以上,就是衰减信号,得去查是不是有资源没释放。

第二组补充验证是线程组数对比。固定单库场景、150 并发,把thread_pool_size从默认值调到 32,五台压测机每台从 10 并发逐步加到 50,测出 TPS 240000、CPU 67%;继续加并发,TPS 与 CPU 的涨幅都不明显;而当并发瞬间冲到 225、250 时,CPU 使用率反而回落到 60%。

这个“并发更高、CPU 反而更低”的现象看着像玄学,其实合理:并发瞬间冲高时,大量请求在队列里排队,真正在跑的线程组还是那 32 个,CPU 自然上不去。它说明这套配置的饱和点在 150~200 并发之间,再往上加并发只是把队列拉长,不会带来吞吐提升。这一条要单独写进结论,因为它是容量规划的直接依据——现网按 150 并发配资源,留 30% 余量,比按 400 并发配要省得多。

5. 避坑与排查:压测环境里最容易翻车的五个点

压测翻车大多数不是数据库的问题,是方案设计的问题。下面五条是这类项目里出现频率最高的,每条按现象、原因、解决三段写,撞上了可以直接对照排查。

5.1 压测机先成为瓶颈:TPS 上不去但数据库很闲

现象:并发加到 200 以后 TPS 不再上涨,但数据库节点 CPU 只有 40%,磁盘 await 也很低,监控上看不出任何压力。

原因:施压端自己扛不住了。单台机器跑 200 以上线程的 JMeter,线程调度、结果写盘、参数读取都会吃掉大量 CPU,真正发出去的请求数远低于设定值。另一种情况是压测机与数据库之间的网络带宽被打满,请求在链路上排队。

解决:先看施压机的 CPU 与网络,再看数据库。超过 150 线程一律改分布式,四台均分;jtl 结果文件写到本地磁盘而不是网络盘;参数文件用 CSV 而非每次读库。改完复测,如果 TPS 随并发重新开始上涨,说明之前测到的“上限”其实是压测机的上限。

5.2 日志级别没改,TPS 被 I/O 吃掉

现象:线程池前后的对比数据差异很小,甚至实验组还不如基线,但 CPU 使用率明显偏高,磁盘写入量也异常。

原因:应用或数据库的日志级别还是默认的 info/debug,每条查询都落盘。压测时 QPS 上万,日志写入的 I/O 开销会直接挤占查询本身的资源,线程池带来的那点收益被完全淹没。

解决:压测前把日志级别统一调到 error,这条要写进方案的环境准备清单,由 DBA 和开发双确认。调完之后先跑一轮小并发验证日志量确实降下来了,再开始正式压测。这个坑我见过不止一次,两次都是白跑一整天。

5.3 阶梯加压步长太大,最优容量点被跳过

现象:40 线程跑得很稳,加到 140 线程直接击穿红线,中间的 80、100、120 全都不知道什么情况,最后只能报一个“系统支持 40 到 140 之间”的模糊结论。

原因:档位跨度太大,而线程池的收益曲线是非线性的。在某一段区间里 TPS 会跃升,跨过这段就进入平台期,再往上就击穿。步长 100 的时候,跃升区间大概率被整段跳过。

解决:步长按预期上限的 10%~20% 取,本次用 40 一档。轮次多了用脚本串起来跑,别用人工盯着。另外每一档都要跑满稳定时长(本次 5 分钟)再取样,起停阶段的毛刺不能算进结论。

5.4 只盯 TPS 不看响应时间与成功率,把失败当成功

现象:报告里 TPS 数字很漂亮,但复现时现网一上线就出问题,回头翻压测数据才发现当时错误率是 3%,只是没人看。

原因:断言配置太弱,或者只看了聚合报告的第一行 TPS。JMeter 默认不校验业务返回内容,接口返回一个错误页也算 200 成功。参数耗尽回绕、主键查空、字段错位,这几种情况都能把成功率做成 100%。

解决:每个事务至少两条断言——返回行数、关键字段与入参一致。CSV 配置里关闭 EOF 回绕,让参数不足以失败形式暴露。看报告时先看错误率和 90% 响应时间,再看 TPS,顺序反了容易被漂亮的数字带偏。

5.5 稳定性测试跑 12 小时才发现连接数泄漏

现象:长跑测试到第 8 小时,TPS 开始缓慢下滑,连接数持续上涨,最后应用侧报连接超时。

原因:线程池参数与连接池参数不匹配。线程池把请求处理能力抬高了,但应用侧连接池上限没动,或者数据库侧的最大连接数没跟着调,长跑过程中连接创建速度大于回收速度,慢慢耗尽。

解决:上线前把应用连接池上限、数据库最大连接数、线程池组数三个数放在一起核对,按“连接池上限 ≤ 最大连接数 × 0.8”留余量。稳定性测试开始前就挂好连接数监控,每 10 分钟采一次,一旦出现单调上升就停下来查,不要等到跑完 12 小时才看。

6. 验收与答辩:把 TPS 曲线讲成一句能落地的结论

到了交付环节,最容易犯的错是把一堆截图和表格堆上去,然后说“性能提升了”。评审的人想听的不是数字,是判断:这套配置该不该上、上了之后容量怎么定、风险在哪。我一般的做法是准备一张一页纸的结论表,所有原始数据放附录,主讲这张表。

结论项数据支撑落地动作
插件该不该上四库 1.32 倍、单库 1.9 倍,成功率均 100%上,先在单库业务试点
容量怎么定32 组线程、150 并发时 TPS 240000、CPU 67%按 150 并发配资源,留 30% 余量
收益什么时候出现80 线程内收益有限,200 线程以上才明显高并发业务优先接,低并发先不动
风险在哪90% RT 从 1ms 升到 2ms,长跑需盯连接数稳定性监控加连接数与 TPS 尾部

讲的时候按“问题—方案—证据—结论”四步走,每步一句话。问题:现网高并发时性能抖动。方案:引入线程池插件,改连接处理模型。证据:四组对照加一组 12 小时稳定性,红线全部守住。结论:插件上线,容量按 150 并发规划。四句话讲完,剩下的时间留给提问。

提问环节高频的三个问题,提前准备好答案。第一个是“1.9 倍是怎么算的”,要明确回答是单库场景下线程池前的满载 131676 对线程池后的满载 250274,并发数不同,比的是各自的满载能力,不是同一并发下的提速。第二个是“为什么四库只涨 1.32 倍”,答案是四套库共享同一实例的 buffer pool 与磁盘队列,混合场景下资源竞争摊薄了收益。第三个是“这个数能搬到现网吗”,诚实回答不能直接搬,压测环境是理想匀速流量,现网有毛刺,所以容量规划留了 30% 余量,并且建议先单库试点再全量。

还有一个技巧:把“线程池前”的那条 TPS 曲线和“线程池后”的那条画在同一张图上,横轴并发、纵轴 TPS。两条线的交叉点和分叉点会自己说话,比任何形容词都有力。图上标三个点——基线满载点、实验组拐点、稳定性工作点,讲的时候手指跟着走,听众的注意力不会散。

从那以后我每次做这类性能方案,都会在写第一行脚本之前先把“验收表长什么样”画出来,哪怕只是草稿纸上的四行表格。指标没定死就开始压测,跑出来的数据大概率要重跑,这个后悔药我吃过两次,不想再吃第三次。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进