压测前TPS 3000,调优后12000:我的MySQL压测实战复盘

简介: 从一次大促前的数据库压测实战出发,完整梳理sysbench压测全流程:环境搭建、四种测试场景设计(OLTP读写混合/只读/只写/点查)、关键指标解读(TPS/QPS/延迟分位数)、常见压测误区排查,以及从压测结果反推配置优化的实操方法。

大家好,我是数据库小学妹👋 我踩过的坑,你别再踩。

六月份大促前一周,领导让我做一轮数据库压测,确认能不能扛住预计的三倍流量。我之前只跑过几次零散的基准测试,从来没有完整做过一次系统性的压测。接到任务后花了两天时间搭环境、调参数、写脚本、跑测试、分析结果,最后发现几个关键配置项调优后TPS从3000提升到了12000。

压测不是跑个工具看个数字就完了。场景设计错了,压出来的数据和真实负载完全对不上;指标看错了,你以为扛得住,上线后直接翻车。今天把压测的全流程完整梳理一遍,从环境准备到场景设计,从指标解读到配置调优,希望我踩过的坑能帮你少走弯路。


一、压测环境准备

压测环境必须和生产环境一致或可对比,CPU核心数、内存大小、磁盘类型是SSD还是HDD、网络带宽、MySQL版本。如果压测环境用HDD而生产用SSD,压出来的数据没有任何参考价值。

我的压测环境是8核16G、SSD云盘、MySQL 8.0.36。目标生产环境是16核64G、SSD、同版本MySQL。压测结果需要按比例估算,但不能简单线性外推。I/O和CPU在不同规格上的表现是非线性的。

安装sysbench很简单,大部分Linux发行版的包管理器都有:

# CentOS/RHEL
yum install sysbench

# Ubuntu/Debian
apt-get install sysbench

数据准备阶段需要先创建一个测试库和测试用户:

CREATE DATABASE sbtest;
CREATE USER 'sbtest'@'%' IDENTIFIED BY 'your_password';
GRANT ALL ON sbtest.* TO 'sbtest'@'%';
FLUSH PRIVILEGES;

然后用sysbench准备测试数据:

sysbench oltp_read_write \
  --db-driver=mysql \
  --mysql-host=127.0.0.1 \
  --mysql-port=3306 \
  --mysql-user=sbtest \
  --mysql-password=your_password \
  --mysql-db=sbtest \
  --tables=10 \
  --table-size=1000000 \
  --db-ps-mode=disable \
  prepare

这里创建了10张表,每张表100万行。table-size的大小会影响测试结果的准确性——太小测试不出大数据量下的性能衰减,太大准备数据耗时太长。我建议表行数至少是生产环境单表行数的十分之一以上,这样索引结构和数据分布才接近真实情况。

特别注意:sysbench 1.0.20对MySQL 8.0的prepared statement支持不稳定,不加--db-ps-mode=disable的话容易误报MySQL thread stack overrun错误,导致压测中断。


二、四种核心压测场景设计

很多新手压测只跑一个OLTP混合读写场景,然后就说“TPS能到8000,稳了”。这完全不够。数据库在不同负载模式下的表现差异巨大,只测一种场景等于只做了一种体检项目。

场景一:OLTP读写混合(模拟日常业务)

sysbench oltp_read_write \
  --db-driver=mysql \
  --mysql-host=127.0.0.1 \
  --mysql-port=3306 \
  --mysql-user=sbtest \
  --mysql-password=your_password \
  --mysql-db=sbtest \
  --tables=10 \
  --table-size=1000000 \
  --threads=32 \
  --time=300 \
  --report-interval=10 \
  --db-ps-mode=disable \
  run

这个场景模拟OLTP系统的典型负载,约70%的读操作(点查加范围查询)和约30%的写操作(INSERT、UPDATE、DELETE的组合)。这是最基础的压测场景,反映的是日常业务的平均性能。

场景二:只读场景(模拟报表/查询负载)

把oltp_read_write换成oltp_read_only。这个场景对读缓存和索引效率非常敏感,用来评估系统在报表查询、只读分析场景下的能力。

场景三:只写场景(模拟OLTP写入负载)

换成oltp_write_only。这个场景模拟的是OLTP写入操作(包含INSERT、UPDATE、DELETE的组合),对写入缓冲、Redo Log刷盘策略、主键索引维护非常敏感。我在这个场景下发现了innodb_flush_log_at_trx_commit=1(每次事务刷盘)导致的写入瓶颈,改成2后写入TPS提升了近40%。

场景四:点查场景(模拟高并发主键查询)

换成oltp_point_select。这个场景模拟的是高并发下的单行主键查询,主要测试缓冲池命中率和锁竞争。如果点查性能差,说明Buffer Pool不够大或者存在锁竞争。

每个场景我跑300秒(5分钟),取稳定阶段(前30秒预热后)的数据。预热阶段的数据不准确,因为MySQL还在加载数据到Buffer Pool,命中率在爬坡阶段。


三、关键指标解读

跑完四个场景后,sysbench会输出一长串数据。但真正值得关注的,其实就四个核心指标。

每秒事务数(TPS):事务是一组SQL操作的集合,sysbench的OLTP事务包含SELECT、UPDATE、INSERT、DELETE。TPS反映的是系统的整体处理能力。我初始压测的读写混合场景TPS是3200左右,调优后达到11500。

每秒查询数(QPS):QPS通常远大于TPS,因为一个事务包含多条SQL。QPS更多反映的是查询层的吞吐能力。

延迟分位数(Latency Percentiles):这个指标比平均值重要得多。平均值20ms看起来很好,但如果P99延迟是500ms,意味着1%的请求要等半秒以上。大促时这1%的用户就会感觉系统卡顿。我重点关注P95和P99——P95代表95%的请求都在这个时间以内完成,P99代表99%的请求都在这个时间以内完成。初始配置的P99延迟在800ms左右,调优后降到120ms。

错误率:压测中出现的超时错误和连接拒绝。错误率应尽可能接近0,具体可接受的阈值需根据业务场景设定——金融场景可能0.01%都不能接受,而日志类业务可能容忍度更高。我在只写场景下出现过5%的超时错误,排查下来是innodb_thread_concurrency限制太紧导致的线程饥饿。

这四个指标需要组合判断:TPS高不代表系统健康。如果TPS很高但P99延迟也高,说明系统在处理大量请求但每个请求都很慢,这是典型的过载表现。正确的判断方式是在P99延迟不超过业务可接受阈值的前提下,TPS越高越好。


四、从压测结果反推配置优化

我的压测调优经历了三个轮次,每轮调一个或两个参数,跑完四组场景看变化。

第一轮:Buffer Pool调大

初始innodb_buffer_pool_size是默认值128MB,对于16G内存的服务器来说太小了。改成8G(总内存的50%)。这个改动对读场景的效果最明显——只读场景TPS从4500提升到7800,因为大部分查询都能从Buffer Pool直接拿到数据,不需要读磁盘。

SET GLOBAL innodb_buffer_pool_size = 8589934592;

MySQL 8.0支持在线调整Buffer Pool大小,不需要重启。

第二轮:Redo Log刷盘策略调整

初始innodb_flush_log_at_trx_commit=1,每次事务提交都强制刷盘,保证数据不丢,但写入性能差。改成2后,每次事务提交写操作系统缓存,每秒刷一次盘。写入场景TPS从2800提升到3900,提升了约40%。

这个改动的代价是:如果服务器断电,最多丢失1秒内的事务数据。对于大多数业务来说这是可以接受的风险。金融级业务建议保持=1,配合sync_binlog=1组成“双1配置”,这是行业标准做法。

第三轮:并发线程数调优

初始innodb_thread_concurrency没设限制(默认0是自动管理),在高并发写入场景下出现线程竞争。改成16后,写入TPS稳定在4200左右——之前波动很大,在2800到3800之间跳。这个参数没有标准答案,需要根据CPU核心数和业务负载模式逐步测试,找到最优值。

最终四轮测试的结果对比:

场景 初始TPS 最终TPS 初始P99延迟 最终P99延迟
读写混合 3200 11500 820ms 120ms
只读 4500 7800 350ms 45ms
只写 2800 4200 1200ms 380ms
点查 8500 15000 50ms 15ms

五、常见压测误区

很多人压测的结果不可用,不是因为工具不好,而是因为方法错了。

第一个误区是用空数据库压测。 刚初始化好的数据库Buffer Pool是空的,数据还没加载,索引也没建立好统计信息。这时候压出来的数据偏低,不能反映真实性能。正确的做法是先做一轮预热——跑一遍全表扫描或随机查询,让数据加载到Buffer Pool,然后再跑正式压测。

第二个误区是压测时间太短。跑30秒就拿结果?这30秒可能正好处于预热阶段或数据刷盘阶段,数据波动大。每个场景至少跑300秒,取稳定区间(排除前30秒预热)的平均值。

第三个误区是只看TPS不看延迟。TPS高但延迟也高的系统,上线后一定会出问题。大量请求在排队处理,用户体验很差。压测报告必须同时给出TPS和P99延迟,并且明确“在P99延迟不超过X ms的条件下,TPS达到Y”。

第四个误区是压测数据和生产数据结构不一致。sysbench默认的oltp测试表结构很简单,只有id、k、c、pad四个字段,没有复杂索引、没有TEXT字段、没有联合索引。如果你的生产表有大量复合索引、全文索引、JSON字段,用sysbench默认模板压出来的结果和生产环境差距很大。我的做法是根据生产表的DDL结构手动创建类似的测试表,再用sysbench的lua脚本做自定义压测。


六、避坑清单

压测环境的磁盘IO性能要和生产一致。我在云服务器上压测时用的是本地SSD,但生产用的是SSD云盘,两者的IOPS和吞吐量不是一个量级。压测结果出来后才发现,同样的配置下云盘的写入TPS只有本地SSD的60%。后来换了和生产一样规格的EBS云盘重新压测,数据才准确。压测前一定先确认存储类型和IOPS上限。

压测时关闭所有非必要的后台进程。MySQL的自动统计信息收集、备份任务、慢查询日志的flush操作——这些后台进程在压测期间会占用CPU和IO资源,导致测试结果偏低且不稳定。我的做法是压测前停掉crontab里的所有定时任务,压测结束后再恢复。但需要注意:在生产环境做压测时,关闭备份任务等操作要谨慎评估风险,避免影响生产数据的正常备份。

每次只调一个参数。这是压测调优的铁律。如果一次改了三个参数然后TPS提升了,你根本不知道是哪个参数的功劳,也不知道另外两个参数有没有副作用。我的做法是建一个调优记录表,每次记录改了哪个参数、改前值、改后值、每个场景的TPS和延迟变化。跑了五轮之后,就能清晰地看到每个参数对性能的影响趋势。

我是数据库小学妹,咱们下篇见 👋


*MySQL 8.0已于2026年4月正式结束生命周期(EOL)。如果你正在搭建新的压测环境或准备上线新系统,建议使用MySQL 8.4 LTS或9.7 LTS版本。8.4 LTS是官方推荐的长期支持版本,维护周期更长,安全更新更有保障。本文中的压测方法和参数调优思路同样适用于8.4和9.7版本。

相关文章
|
2月前
|
缓存 监控 NoSQL
命中率98%跌至23%,17条告警齐发:Redis缓存三大故障复盘
从618促销缓存雪崩事故切入,深度解析缓存穿透、击穿、雪崩的底层机制、生产级防御方案与监控告警策略,附布隆过滤器实现和分布式锁代码
|
2月前
|
安全 关系型数据库 MySQL
切换从32秒缩到10秒,MHA到InnoDB Cluster升级复盘
从MHA停维护近十年、份额跌至12%的现实切入,完整记录从MHA一主两从升级到InnoDB Cluster的路径,含MySQL Shell建集群、Router切换、数据迁移与验证下线
|
2月前
|
存储 搜索推荐 关系型数据库
纯向量库架构上线两周出事故,我帮他们重构后发现了3个选型误区
从一次生产事故出发,拆解向量数据库爆火的真实原因,深入底层索引机制和架构取舍,分析融合趋势。给从业者一个清醒的判断框架。
|
2月前
|
SQL 人工智能 关系型数据库
实测四大AI模型写SQL,表现差距不小
基于2026年8月已公开的主流模型版本(GPT-5.5、Claude Opus 4.7、Qwen3、Kimi k2.6),实测四个真实业务SQL场景。深入分析基准测试与真实场景的鸿沟、SQL幻觉根因,从准确性、可读性、性能三维度给出量化测评。
|
2月前
|
存储 固态存储 关系型数据库
DBA凌晨查账单:每月5万的云数据库竟有一半在空转,我的六个优化动作和数据验证
从一次真实的云数据库成本优化复盘出发,分享实例规格合理选型、冷热数据分层、存储压缩、弹性伸缩策略、清理历史数据、预留实例规划六个关键步骤,附优化前后的成本对比数据和操作要点。
|
2月前
|
存储 关系型数据库 MySQL
读写混合TPS差六倍,PostgreSQL与MySQL架构差异实测
从架构设计、索引实现、事务隔离、复制机制、运维体验五个维度深度对比PostgreSQL与MySQL,覆盖MySQL 9.0向量检索与PostgreSQL 17新特性,附权威基准数据和选型决策框架
|
2月前
|
存储 架构师 数据库
从DBA到数据架构师:技术债务管理是分水岭
“架构债”在业务快速迭代中被不断放大,最终成为系统稳定性的定时炸弹。本文从数据架构的视角出发,拆解数据库技术债务的四种典型类型,提供识别、评估和偿还的完整方法论,帮助读者从“数据库管理员”升级为“数据架构师”。
|
2月前
|
存储 固态存储 关系型数据库
从月账单5万到3.5万:云数据库成本优化的完整复盘
上云本应是降本增效,但很多企业上云之后,账单反而越滚越大。实例规格买高了、历史数据堆在SSD上、测试环境没人关、过期快照没清理——每一笔费用都在悄悄累积。本文从云账单的三大“黑洞”出发,拆解云成本失控的根因,给出实例降配、冷热数据分层、僵尸资源清理三条可落地的优化路径,帮助DBA和运维工程师用数据驱动成本优化,让每一分钱都花在刀刃上。
|
2月前
|
SQL 运维 监控
慢查询日志的“高级用法”:从找慢SQL到做容量规划
慢查询日志是DBA最熟悉的工具,但大多数人只用它来找“跑得慢的SQL”。如果只做到这一步,你只用了慢查询日志20%的价值——剩下的80%是建立性能基线、预测容量瓶颈、评估优化效果、发现潜在风险。本文从慢查询日志的进阶用法出发,讲解如何通过持续记录慢查询建立性能基线、如何通过慢查询趋势预测容量瓶颈、如何将慢查询日志从“故障排查工具”升级为“容量规划工具”,帮助读者从“出了问题再查”升级到“看着趋势主动调整”。
|
2月前
|
存储 关系型数据库 MySQL
查询从45秒降到0.3秒,存储从1.2TB缩到180GB:IoT时序数据选型复盘
5万台IoT设备日增4.3亿行数据,MySQL三天崩溃的完整复盘。从写入模型、B+树瓶颈、Gorilla压缩原理对比时序库与关系型数据库的根本差异,含宽窄表重构SQL、冷热分离迁移策略、time_bucket查询优化,以及3条实战避坑经验。