ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

MySQL 8.0性能基准测试实战:安装配置到sysbench压测全解析

MySQL 8.0性能基准测试实战:安装配置到sysbench压测全解析

1. MySQL 8.0值得关注的几个变化

写这篇博文之前,我刚好帮一个朋友处理了他那边测试环境MySQL性能摸底的需求。他的场景很典型:新购置了几台物理服务器,打算从旧版本数据库迁移到MySQL 8.0,但团队里没人正经跑过基准测试,对8.0的性能心里没底。安装、初始化、压测、看结果,这一套流程走下来,踩了一些坑,也沉淀了不少经验。

先说说为什么选MySQL 8.0而不是继续用5.7。这个问题的答案,直接决定了后续安装和测试的路线。我自己的看法是,如果项目是从零开始、没有历史包袱,那8.0应该是当下的默认选项。官方对5.7的延伸支持已经进入倒计时,这意味着安全补丁和关键bug修复会越来越滞后,对生产环境是实打实的风险。

从功能层面看,8.0做了两个特别影响日常使用的改动。

第一个是默认字符集变成了utf8mb4。这意味着建表时不用再显式指定CHARSET=utf8mb4,从源头避免了emoji、生僻字存不进去的尴尬问题。第二个是默认身份认证插件换成了caching_sha2_password。老版本的mysql_native_password在8.0里降级成了兼容选项。这个变化对老客户端影响很大,比如Python 3.x里某些旧版本的pymysql、Java里老版本的Connector/J,如果不做兼容处理,连库时直接报认证失败。

还有一些容易被忽略但实际影响操作的细节:

  • 系统表结构和数据字典全面重构。mysql.user表不再直接存储密码散列,用户权限信息从数据字典读取,导致以前那种改密码字段的骚操作彻底失效。想重置密码,只能走官方推荐的ALTER USER语法或skip-grant-tables流程。
  • 参数命名更规范。比如query_cache_size被彻底移除,因为查询缓存这个特性在8.0里被删掉了。同步binlog相关的expire_logs_days改名为binlog_expire_logs_seconds,很多从5.7迁移过来的配置文件直接启动失败,报Unknown system variable,原因就在这。
  • InnoDB的性能优化。底层改了预读策略、自适应哈希索引的触发逻辑、redo log的子信道并发写入等。官方自己的测试数据显示高并发读写场景下吞吐量比5.7有明显提升,但具体能提升多少,还得看硬件和实际负载特征,这也是我们做基准测试的原始动力——不看自己机器上的真实数据,心里永远没底。

这也引出了这篇文章的主题:从零开始在一台干净的Linux服务器上装好MySQL 8.0,完成初始化配置,然后分别用数据库圈子里用得最多的两个基准测试工具把机器的性能底摸清楚,最后教大家如何看穿测试报告里的数字,判断机器真正的负载能力。

2. 安装方式对比与选型建议

MySQL 8.0的安装方式非常多,官方提供二进制tar包、RPM包、APT源,第三方还提供Docker镜像。对生产环境而言,我的建议从高到低排序是:操作系统官方源、MySQL官方Yum/Apt源、二进制tar包。Docker方式不是不能用,但至少不适合作为物理机部署的主力方案,性能和运维习惯上都有一些别扭的地方。

拿我这次实际操作的环境举例:一台CentOS 7.9的机器,8核16线程CPU、32GB内存、两块NVMe SSD做软RAID 1。这个配置不算高档,但很符合一般中型业务测试环境的底子,跑基准测试具备一定的参考意义。

2.1 操作系统自带源与官方源的区别

CentOS 7自带的AppStream源里通常只有MySQL 5.7,在CentOS 8上才有MySQL 8.0的rpm包。如果你不想折腾,又想用8.0,最省事的办法是配置MySQL官方Yum仓库。

配置过程就三步:

  1. 下载官方仓库rpm包
  2. 安装该rpm包(它只负责写入Yum源定义,不实际安装MySQL)
  3. 用yum install mysql-community-server装服务端

官方源的好处是版本跟进快,安全补丁发布后能第一时间拉取到。社区版和企业版二进制兼容,将来如果购买了商业订阅,切换也很平滑。缺点是官方源在国内某些网络环境下速度不太稳定,这时候可以考虑换国内镜像。

2.2 二进制tar包方式:适合特殊场景的灵活方案

为什么还需要单独讲二进制tar包?因为有些场景根本没法走Yum:比如内网环境与外界隔离,yum源拉不通;比如系统是精简版,没有配置任何第三方仓库;再比如你想同时跑多个MySQL实例,不同版本独立部署。

tar包的安装逻辑本质上就是"解压即用"。官网下载mysql-8.0.x-linux-glibc2.12-x86_64.tar.xz,解压到指定目录,然后手动创建数据目录、初始化、配置启动。整个过程不依赖系统的rpm数据库,完全可控。我第一次尝试这个方案的时候,就遇到一个典型的坑:CentOS 7自带的glibc版本是2.17,官方README里写的glibc2.12说明最低兼容到2.12,但实际运行中还是提示缺少libaio和libnuma两个动态库。原因在于8.0的二进制默认链接了libaio,不装的话mysqld --initialize直接报错。

2.3 我推荐的安装路径

如果你跟着这篇文章走,环境是CentOS 7.x或Rocky Linux 8.x,建议直接采用官方Yum源方案,步骤最少、依赖问题最少、最接近生产环境操作的普遍习惯。

我这次实际用的就是官方Yum源。补充一个在新装系统上特别实用的小技巧:装完系统后先执行一次yum install -y epel-release把EPEL源加上,再安装MySQL官方源。EPEL里有个叫percona-toolkit的包后面做测试和排查时经常用到,提前装好省得后面临时补。

3. 安装全流程与初始化中的关键细节

3.1 用官方Yum源完成服务端部署

这部分的命令序列我再完整走一遍,并标注每一步的意图:

# 1. 下载并安装MySQL官方Yum仓库配置文件 wget https://repo.mysql.com/mysql80-community-release-el7-7.noarch.rpm rpm -ivh mysql80-community-release-el7-7.noarch.rpm # 2. 检查仓库是否生效 yum repolist enabled | grep mysql # 3. 安装服务端(这一步会自动安装mysql-community-client等依赖) yum install -y mysql-community-server # 4. 启动服务并设置开机自启 systemctl start mysqld systemctl enable mysqld

装完以后,用systemctl status mysqld或者直接mysql -uroot -p登录会发现问题:8.0首次启动时会自动生成一个临时密码,位置在/var/log/mysqld.log里,用grep 'temporary password'可以捞出来。这是MySQL 8.0做得比较贴心的设计,避免安装后空密码裸奔。

拿到的临时密码先别急着用,因为默认的密码策略比较严格:至少8位、必须包含大小写字母、数字和特殊字符。第一次登录后系统会强制你先改密码,否则任何操作都做不了。

mysql -uroot -p # 输入临时密码 ALTER USER 'root'@'localhost' IDENTIFIED BY 'Your_Strong_Passwd_2024!';

3.2 数据目录初始化的两种方式对比

官方Yum源安装路径下,数据目录默认是/var/lib/mysql,服务启动时如果发现目录为空,会自动完成初始化。这种方式叫自动初始化,对新手最友好,但对生产环境来说不够精细。

如果想自己控制初始化过程,可以用手动初始化方式:

# 先停止服务,清空数据目录(注意备份) systemctl stop mysqld rm -rf /var/lib/mysql/* # 手动初始化,--user指定运行用户,--basedir指定安装目录 mysqld --initialize --user=mysql --basedir=/usr --datadir=/var/lib/mysql

两种方式生成的数据字典结构完全一样,差异主要在于对初始化日志的理解——手动方式可以更清楚地看到初始化过程有没有警告。我遇到过一次因为/etc/my.cnf里配了过时的参数导致初始化失败的情况,手动方式下错误信息直接打印到终端,排查起来比翻日志快得多。同时也建议在初始化时用--log-error参数把错误日志单独指到自己的目录,别混在系统日志里。

3.3 刚装完必调的5个参数

安装完成、能登录、能建库建表,这只是"能用"的状态。"好用"还需要在配置文件/etc/my.cnf里调几个参数。这些参数如果装完不动,跑基准测试的时候性能会打很大折扣。下面是我这次的最终配置,标注了每个参数的用途:

[mysqld] # 数据文件路径 datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock # InnoDB缓冲池大小,决定热点数据的装载能力,设为物理内存的60%-70% innodb_buffer_pool_size=20G # 日志文件大小,8.0里redo log默认由innodb_log_file_size控制 innodb_log_file_size=1G # 事务提交刷盘策略,追求最高性能可设为2,但存在崩溃丢1秒数据风险 innodb_flush_log_at_trx_commit=2 # 连接数上限,压测并发数高时这个值太大会导致连接数不足 max_connections=2000 # 默认字符集与排序规则 character_set_server=utf8mb4 collation_server=utf8mb4_0900_ai_ci # 关闭符号链接,安全加固 symbolic_links=0

innodb_buffer_pool_size为什么这么重要?简单理解,InnoDB读取数据时优先在内存里找,找不到才去磁盘,内存命中率直接决定随机读的性能。缓冲池设置过小,热点数据频繁被淘汰,磁盘IO会成为瓶颈。一次压测下来,如果iostat里%util一直满载而TPS上不去,八成是缓冲池不够用或者没预热。这里补充一个细节:innodb_log_file_size在8.0里虽然还能用,但官方更推荐用innodb_redo_log_capacity来管理redo log总容量,默认值是100M,线上环境建议调到1G以上。

innodb_flush_log_at_trx_commit这个参数值得单独讲讲。它控制的是事务提交时redo log的刷盘策略。取值1意味着每次事务提交都强制把日志刷到磁盘,最安全但最慢,适合对数据安全要求高的场景;取值2意味着先写入操作系统缓冲区,每秒刷一次盘,性能好很多,但数据库进程崩溃时可能丢最近1秒的已提交事务;取值0则是交给系统自己决定刷盘时机,性能极好但崩溃丢失窗口更大。基准测试场景下用2比较合理,既贴近很多互联网生产环境的实际选择,又能反映相对真实的性能上限。如果你压测时用的是默认值1,得到的TPS数字会明显偏低,不能作为容量规划依据。

改完配置要重启服务:

systemctl restart mysqld

重启后可以用SHOW VARIABLES LIKE 'innodb_buffer_pool_size';确认参数生效。生产环境加参数时还有一个细节——最好先SET GLOBAL动态调整,观察一段时间再写进配置文件,避免改错导致实例起不来。按上面配置测试环境重启时出现过一次失败,排查后是my.cnf里配了不存在的query_cache_size参数导致的,改成去掉后启动正常。MySQL 8.0删除的特性参数,配置文件里残留了就会报启动失败,所以从5.7迁移配置时一定要清理过时参数。

4. 基准测试前的环境检查与测试库准备

安装和基础参数调完之后,可以开始做准备工作了。这一步很多人会跳过,我觉得是不对的。测试环境没校准,压测出来的数字是垃圾。这里的"校准"不是特别玄乎的东西,就是确认操作系统层面的几个状态。

用Linux的vmstat、iostat、perf简单看一眼系统有没有异常负载,之前没跑过业务的测试机上这一步问题一般不大。更关键的是文件系统挂载参数。MySQL默认数据目录在/var/lib/mysql,如果这是一个独立分区且没加noatime挂载参数,每次读都会触发atime更新,增加额外的IO开销。查看方式:

df -h /var/lib/mysql mount | grep /var/lib/mysql

没有noatime的话,在/etc/fstab里加上重启生效。操作不复杂,但很多人确实不知道,等压测完对比别人同配置机器的数字发现比人家低,到头来才发现是这个细节,很浪费时间。

4.1 创建压测专用账号与数据库

MySQL的root账号权限太大,压测时最好单独建一个专用账号,一方面防止误操作,另一方面也贴近生产环境的最小权限原则:

CREATE DATABASE sbtest DEFAULT CHARACTER SET utf8mb4; CREATE USER 'sbtest'@'%' IDENTIFIED BY 'Sbtest_2024!'; GRANT ALL PRIVILEGES ON sbtest.* TO 'sbtest'@'%'; FLUSH PRIVILEGES;

注意到我特意指定了utf8mb4字符集。MySQL 8.0默认就是它,这里再显式指定一遍是为了保险,同时也能排除字符集不同导致的排序开销差异。有前辈做过测试,latin1和utf8mb4在大量字符串排序场景下性能差距能到10%以上,测试库既然是为了测性能,就不该让字符集成为干扰因素。

4.2 压测工具的选型逻辑

市面上最常见的MySQL压测工具有两个:sysbench和mysqlslap。

sysbench是开源界的事实标准,由Percona团队长期维护,支持自定义lua脚本、多线程压测、多种测试模式(oltp_read_only、oltp_read_write、oltp_write_only等),能输出非常细致的TPS、QPS、延迟分位数数据,做容量评估和硬件摸底都靠它。Percona的分支版本还额外支持从测试结果里自动生成图表报告。

mysqlslap则是MySQL官方自带的客户端工具,装完mysql-community-client就有,优点是零额外安装成本,能模拟并发加载,但功能比较基础,输出维度少,不适合做精细化压测和分析。

我的建议:性能摸底以sysbench为主,mysqlslap作为补充验证,两个工具的结论交叉比对。原因很简单:sysbench的报告更贴近生产环境真实负载特征,mysqlslap更像是一个"冒烟测试"工具。等下我会给出两个工具的具体用法和结果解读。

4.3 sysbench的安装

sysbench的安装我用的是EPEL源:

yum install -y epel-release yum install -y sysbench sysbench --version

版本是1.0.x,就够用了。注意某些镜像源的sysbench版本可能比较旧,如果输出的--version是0.4.x,建议直接卸载后从源码编译,不然很多参数对不上。0.4和1.0的语法差别非常大,网上很多教程是0.4的写法,照着抄容易翻车。

5. 用sysbench跑正式的基准测试

5.1 数据准备阶段的参数设计

压测的第一步是准备测试数据。sysbench用oltp_common脚本在目标库里生成指定数量的表和指定行数的数据。我的测试配置如下:

sysbench /usr/share/sysbench/oltp_read_write.lua \ --mysql-host=127.0.0.1 \ --mysql-port=3306 \ --mysql-user=sbtest \ --mysql-password='Sbtest_2024!' \ --mysql-db=sbtest \ --tables=10 \ --table-size=1000000 \ --threads=16 \ --time=300 \ --report-interval=5 \ prepare

参数含义拆解:

  • --tables=10 --table-size=1000000:生成10张表,每表100万行。数据量不是越大越好,太大会让prepare阶段耗时过长,太小又可能全部命中内存,测不出磁盘真实能力。1000万行在32GB内存的机器上配合20G缓冲池,是一个相对合理的量级。
  • --threads=16:压测线程数,通常建议等于或略大于CPU核心数。准备数据阶段也用16线程,是为了和后续压测保持一致节奏。
  • --time=300:压测持续时间300秒。时间太短,预热不充分,数据不稳定;太长,浪费测试时间且容易把磁盘写到过热。5分钟是我习惯的中庸值。
  • --report-interval=5:每隔5秒打印一次实时统计,可以看到性能是否波动、有没有周期性抖动。

prepare过程会跑一阵,1000万行普通机械盘可能要十几分钟,NVMe上会快很多。如果中途报table already exists,说明之前有残留,可以用sysbench ... cleanup清理后重新prepare。

5.2 正式压测与输出解读

数据准备好以后,把prepare改成run就开始正式压测:

sysbench /usr/share/sysbench/oltp_read_write.lua \ --mysql-host=127.0.0.1 \ --mysql-port=3306 \ --mysql-user=sbtest \ --mysql-password='Sbtest_2024!' \ --mysql-db=sbtest \ --tables=10 \ --table-size=1000000 \ --threads=16 \ --time=300 \ --report-interval=5 \ --rand-type=uniform \ run

这里我额外指定了--rand-type=uniform,意思是随机数的分布模式采用均匀分布。sysbench默认是special模式,会让热点集中在少量数据行上,测出来的TPS会虚高。改成uniform更接近真实业务的随机访问特征。如果你测试的是偏向"最近热数据"的业务,可以试--rand-type=pareto模拟二八分布,两种结果差异很大,选型时要明白自己到底在模拟什么。

压测结束后的输出是下面这个结构:

SQL statistics: queries performed: read: 3258406 write: 930974 other: 465487 total: 4654867 transactions: 232741 (776.00 per sec.) queries: 4654867 (15519.80 per sec.) ignored errors: 0 (0.00 per sec.) reconnects: 0 (0.00 per sec.) General statistics: total time: 300.0242s total number of events: 232741 Latency (ms): min: 0.97 avg: 20.60 max: 391.42 95th percentile: 31.58 sum: 4794652.62 Threads fairness: events (avg/stddev): 14546.3125/344.63 execution time (avg/stddev): 299.6656/0.05

重点看三个指标:

  • transactions (776.00 per sec.):TPS,每秒处理的事务数。这台8核16线程、NVMe盘、20G缓冲池的机器在16线程混合读写下跑到776 TPS,属于正常偏好的水平。
  • queries (15519.80 per sec.):QPS,每秒查询次数。读写混合模式下,QPS和TPS的比例关系取决于每条事务包含的SQL数量,这个值也可以作为后端应用容量规划的一个参考。
  • Latency 95th percentile: 31.58ms:95%请求的延迟都低于31.58ms。这代表绝大多数请求的响应体验,比平均值更有参考价值,平均值容易被极端值拉偏。

可以从两个角度判断这台机器的性能好坏。一是纵向看趋势:多次压测的TPS是否稳定,波动大说明系统存在不稳定因素,比如IO抖动或CPU降频。二是横向看基准:同样的机器,装MySQL 5.7并调相同参数跑同一套测试,得到的数字对比。8.0相对5.7在混合读写场景粗略来看通常能提升15%-30%。但是,这句话仅供参考,每台机器、每个负载特征都不同,只有自己跑出来的数据才是决策依据。

5.3 阶梯式并发测试的意义

上面那次只测了16线程这一个点。生产环境往往需要知道系统在8线程、32线程、64线程下的表现,才能找到最佳并发度区间。通常的处理方式是从小到大递增跑,每次只改--threads参数,其他保持一致:

for t in 8 16 32 64; do sysbench /usr/share/sysbench/oltp_read_write.lua \ --mysql-host=127.0.0.1 \ --mysql-port=3306 \ --mysql-user=sbtest \ --mysql-password='Sbtest_2024!' \ --mysql-db=sbtest \ --tables=10 \ --table-size=1000000 \ --threads=$t \ --time=120 \ --report-interval=5 \ --rand-type=uniform \ run done

测试中每完成一次run,建议用cleanup+prepare重新准备数据,不然前面测试留下的递增/递减索引页碎片会影响后续测试的公平性。确保每次压测的数据页都处于同一状态,结果才具有可比性。

把TPS和平均延迟以并发数为横轴画成曲线,你会看到一种典型形态:并发数上升初期TPS快速增长;达到一个临界点后增速放缓甚至下降,延迟开始明显抬升。那个拐点,就是这台机器在实际负载下最合理的并发承受区间。配套压测过程中可以另开一个终端跑top和iostat,对照CPU使用率和磁盘IO负载,可以更清楚地看出瓶颈到底在哪个维度。

6. 结果解读、瓶颈排查与值得收藏的优化清单

6.1 压测结果不理想时,先别急着调参数

很多人在压测结果不理想时第一反应是继续往my.cnf里加参数,我的建议是先确认瓶颈在哪,再动手调参,否则可能白忙活。排查顺序如下:

  1. CPU维度:跑top看us和sy的比例。sy(内核态开销)过高,说明系统调用、上下文切换太频繁,常见原因是连接数过多或网络中断频繁。
  2. 内存维度:跑free -h看available是否充足。如果频繁swap,缓冲池配置再大也白搭。
  3. 磁盘维度:跑iostat -x 1看%util和await。%util持续100%但TPS不高,说明磁盘跟不上;await高但%util不高,可能存在IO队列排队问题。
  4. 网络维度:本机压测时基本不涉及,但跨机器压测时iftop观察网卡流量是否打满。

我用这套思路排查过一次:某次在8核VM上压测,TPS始终上不了500,top显示sy占用超过60%。最后发现是虚拟机CPU资源被限制导致的,不是MySQL配置问题。这类"环境瓶颈"如果不检查,调参数调一晚上也调不出来。

6.2 MySQL参数优化的常见误区和有效手段

推荐几个在8.0里效果显著且不容易踩坑的优化方向:

第一个方向:调整innodb_io_capacity和innodb_io_capacity_max这两个参数控制InnoDB后台刷脏页的IO速率上限。默认值是200,而现在的NVMe SSD轻松能到几千甚至上万IOPS。刷脏页速率不够,会导致脏页堆积,最终在前台产生"卡顿"效应,表现为压测中延迟突然飙高。建议把innodb_io_capacity设为磁盘IOPS的80%左右,innodb_io_capacity_max设为上限值。用fio之类的工具先测一下磁盘基准IOPS,再填参数,别拍脑袋。

第二个方向:合理设置innodb_buffer_pool_instances这个参数决定缓冲池被分成多少个实例,每个实例独立管理内存块,能减少并发访问时的内部锁竞争。建议值是innodb_buffer_pool_size / 1G,比如20G缓冲池可以分成8个实例(官方上限是64)。压测验证一下,高并发下有时能带来5%左右的提升。

第三个方向:暂时关闭或调低binlog相关开销如果测试环境不要求数据恢复和主从同步,可以先把sync_binlog=0和innodb_flush_log_at_trx_commit=2搭配使用,能显著提升读写TPS。但这只适合测试环境或对数据安全要求极低的场景。生产环境永远优先考虑数据不丢,性能差那么一点是可以接受的。

6.3 用mysqlslap做快速冒烟验证

sysbench跑完以后,可以再用mysqlslap补充验证一轮。mysqlslap的优势在于它是官方自带的,不用额外装东西,语法也简单:

mysqlslap --host=127.0.0.1 --port=3306 --user=sbtest --password='Sbtest_2024!' \ --concurrency=32 \ --iterations=10 \ --number-int-cols=5 --number-char-cols=5 \ --auto-generate-sql \ --engine=innodb \ --number-of-queries=10000

这条命令的意图是:模拟32个并发连接,执行总共10000条自动生成的查询,重复10轮取汇总数据。输出会给出每轮的平均耗时。mysqlslap的脚本逻辑比sysbench简单很多,测试出的数据仅可作参考。

一个实操技巧:把sysbench跑出来的TPS作为Capacity Planning数值,把mysqlslap的结果当作"确认没有明显配置错误"的冒烟测试。两者结合使用,既能评估极限性能,又能快速判断配置是否健康。

6.4 我留下的一个扩展建议

压测完你以为就结束了吗?其实还有一件事值得做——收集MySQL本身的内部状态指标。压测过程中开另一个会话执行SHOW GLOBAL STATUS LIKE 'Innodb%';,重点关注Innodb_buffer_pool_read_requests(缓冲池逻辑读次数)和Innodb_buffer_pool_reads(物理读次数),两者的比例就是缓冲池命中率。高命中率说明内存配置合理,低命中率说明innodb_buffer_pool_size偏小或者测试数据量太大。这个指标比单纯看TPS更能说明"你的配置和你的数据是否匹配"。

7. 遇到过的典型报错与处理方法

最后把这次安装和压测中遇到的几个典型报错记录下来,给同行们做一个排查索引。这些错误都很有代表性,遇到了能快速定位。

7.1 认证插件导致的客户端连接失败

错误信息:Authentication plugin 'caching_sha2_password' cannot be loaded

场景:老版本客户端(mysql-connector-java 5.x、pymysql 0.9.x等)连接MySQL 8.0时报错。

原因:8.0默认的认证插件是caching_sha2_password,老客户端不支持。

处理办法:建议优先升级客户端库版本。如果实在无法升级,可以在MySQL里将该用户的认证插件修改为老式插件:

ALTER USER 'sbtest'@'%' IDENTIFIED WITH mysql_native_password BY 'Sbtest_2024!';

但要注意这是"向后兼容"的操作,能不用就不用。8.0后续版本对mysql_native_password的兼容迟早要收紧,趁早升级客户端是正道。另外,即使升级了客户端,也要确认连接串里没有写死useSSL=false之类的旧选项,SSL相关的握手失败报错也很常见。

7.2 内存配置过高导致启动失败

错误信息:InnoDB: Cannot allocate memory for the buffer pool

场景:把innodb_buffer_pool_size配置得很大,比如机器只有8G内存却配了16G。

原因:MySQL实例在初始化缓冲池时,需要一次性申请对应大小的内存映射,内存不足直接启动失败。

处理办法:按物理内存的60%-70%规划即可,比如8G内存配置5G缓冲池。另外注意,如果机器上还跑了其他应用,比如Java服务或Redis,要预留它们的空间。

7.3 大事务提交时磁盘满导致崩溃

错误信息:InnoDB: Error number 28 means 'No space left on device'

场景:压测过程中写入量巨大,数据目录所在分区被写满。

原因:测试数据加上redo log、binlog、undo log把磁盘写爆了。

处理办法:压测前务必确认df -h /var/lib/mysql至少留有测试数据量2倍以上的剩余空间。另外注意,8.0的redo log可以动态调整容量,同时确保binlog有合理的max_binlog_size限制和expire_logs_days清理策略,别让日志无限增长把磁盘挤爆。

7.4 超过最大连接数限制

错误信息:Too many connections

场景:压测并发数超过max_connections。

处理办法:测试前把max_connections调大(比如2000),同时留意操作系统的ulimit -n,文件描述符限制也要同步抬高,否则MySQL进程会因为句柄不够而提前拒绝连接。检查命令:

ulimit -n # 看当前限制 ulimit -n 65535 # 临时调高,或写入/etc/security/limits.conf

8. 写在最后的一点体会

整个安装、配置、压测流程走完,我个人最大的感受是:MySQL 8.0的部署门槛其实比5.7更低,安装流程不会更复杂,真正的难度在于新特性带来的心智模型变化。字符集、认证插件、参数体系这些"默认值"的变化,会让一些老手在初次接触时觉得不顺手,但适应之后会发现它其实更规范、更安全。

基准测试这件事,本质上是在回答一个问题:我的机器和我的MySQL配置,到底能扛住多少业务量。这台测试机最终在16线程混合读写下稳定跑到776左右的TPS,95%延迟31ms多,对这个配置级别的物理机来说是个健康的数据。如果你照着本文的流程在自己的机器上跑,得到的数字和我的有出入,先不要怀疑操作出了问题——检查硬件配置、参数调优、磁盘类型,逐一对比下来,答案自会出现。

最后提醒一个很多教程不会写到的细节:压测结束后,记得跑一次sysbench ... cleanup把测试数据清理干净,别把一堆sbtest表留在库里影响后续使用。如果你打算把测试数据库保留下来做调优的对照组,那也要有个清晰的归档和命名习惯,别等三个月后跑业务发现库里有几千万行压测垃圾数据,那滋味可不好受。

数据库性能摸底这种事情,没有标准答案,只有相对合理的数据。希望这篇记录能帮你少踩几个坑,省下排查的时间,静下心来好好分析那一串串数字背后的真实含义。

RELATED READING

延伸阅读

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