☰
MySQL 8.0安装配置与sysbench基准测试实战指南
2026/10/20 22:16:37 网站建设 项目流程

说实话,MySQL 8.0出来也有好几年了,可直到现在,我身边还是有不少同行对它的印象停留在“5.7加了个版本号”。实际上,8.0这一代把数据字典、认证插件、优化器、默认字符集全部重做了一遍,安装和调优的思路跟5.7完全是两码事。这篇东西我不打算给你念文档,就以自己实际部署过的经历为主线,走一遍MySQL 8.0的安装、基础配置、sysbench压测和问题排查,把那些文档里不会写、以及我踩过的坑一并讲清楚。刚入门的可以照着步骤做,老手也能重点看看压测这部分的方法论。

1. 为什么选MySQL 8.0:版本特性与适用场景

1.1 8.0相比旧版的实质性变化

先说最直观的变化:数据字典。5.7时代,表结构、元数据分散在.frm文件里,InnoDB自己还要维护一部分信息,两边一旦不一致,就是各种奇怪故障。8.0把元数据全部收归到统一的数据字典表中,和InnoDB引擎实现真正解耦。你做完初始化后去看数据目录,会发现少了一堆.frm文件——这不是安装坏了,而是架构变了。带来的好处是DDL过程中的一致性更强,崩溃恢复也比以前干净,但副作用是数据字典本身也变成了需要重点备份的系统数据,不能只盯业务库。

第二个直接影响业务的改动是默认字符集。8.0把默认字符集定为utf8mb4,排序规则默认是utf8mb4_0900_ai_ci。这里要特别提醒一句:0900排序规则和5.7时代常用的general_ci在字符权重、大小写敏感性细节上并不完全一样。如果老系统里有些查询依赖特定排序结果,迁移后最好拿线上SQL跑一轮比对,不要想当然。

第三个变化是特性层面的。窗口函数、CTE(公共表表达式)是SQL写法上的大杀器,以前用临时表、变量硬拼出来的排名和同比环比逻辑,在8.0里经常一条语句就能写清楚。另外不可见索引对DBA非常友好,可以在不影响线上SQL的情况下验证新索引的效果;直方图统计能帮优化器更准确判断非均匀分布字段的基数,这些都是5.7里没有的东西。

1.2 适用场景与选型建议

我的建议很简单:新项目直接用8.0,不用犹豫。只要不涉及特别老旧的客户端驱动(后面会讲认证插件坑),8.0的SQL能力和性能表现在当前阶段都是最优解。尤其是业务里有复杂统计报表、在线分析类查询的,窗口函数带来的SQL简化非常明显。

对于已经在跑5.7的老系统,升级8.0是可做但不赶早的事。重点排查对象是存储过程、触发器、自定义函数、老旧的SQL语法,这些在8.0里可能会报兼容性错误。至于还在用5.5、5.6的存量库,跨大版本升级不是换个包那么简单,建议先拿一个测试环境跑完整的应用回归。还有一类场景我不建议盲目迁移:如果业务非常简单,就是点查和写入,团队对5.7又磨合得极熟,那维持现状也没问题。8.0的优势在这种场景下体现不出来,迁移的沉没成本反而不值。

注意:8.0把查询缓存(Query Cache)整块移除了。如果有人告诉你“我们库开了query cache,性能全靠它”,就要提醒他,升级后这部分红利会消失,需要重新评估SQL本身和索引质量。

2. 安装前的整体设计:版本选择与系统参数规划

2.1 版本与安装方式选择

MySQL官方提供了三种常见安装形态:通用二进制tar包、发行版自带rpm/deb包、源码编译。我个人的生产环境首选是通用二进制tar包,原因很简单:逻辑清晰,不绑架系统包管理器。rpm包虽然安装省事,但有时候会被系统库依赖带走节奏,卸载、升级时容易留下残余配置;源码编译则是没事找事,除非你要改内核代码或者做特殊裁剪,否则编译出来的性能差异微乎其微。

版本选择上,我的做法是选定当前最新的稳定8.0小版本,而不是最新研发大版本。小版本之间向前兼容,同时会补安全修复,没必要抱着旧小版本当稳定。下载时顺手核对一下glibc版本和系统环境是否匹配,这一步能避免后面初始化时的很多幺蛾子。

安装方式优点缺点适用场景
通用二进制tar包路径可控、升级简单、逻辑透明需要手动做初始化和管理生产环境首选
rpm/deb包安装快、自动注册服务与系统包管理耦合深、升级受发行版约束测试环境、快速交付
源码编译可定制编译参数耗时长、维护成本高特殊定制需求

2.2 系统层面的参数规划

安装MySQL之前,我的习惯是先看机器规划,而不是先解压。最重要的一笔账是内存。InnoDB buffer pool是MySQL的“热数据缓存”,它的大小基本决定了大部分查询能不能在内存里解决。如果这台机器专门跑MySQL,没有其他吃内存的服务,buffer pool可以给到物理内存的60%~70%。举例来说,32G内存的机器,我给InnoDB buffer pool分20G左右,剩下12G留给OS page cache、连接线程、排序缓冲和临时表。如果机器上还跑着其他应用,那缓冲池就要保守一点,40%~50%。

磁盘规划比很多人想的重要。我的原则是数据文件、redo log、binlog三者的IO路径尽量分开。数据文件是随机读写为主,binlog是顺序写,redo log是高频小组写,它们的IO特征不同,堆在同一块盘上,高并发时互相拖累。有条件的话,数据目录放SSD,binlog放独立磁盘,redo log放在低延迟的本地盘上。压测的时候,这一项的差距会直接体现在TPS和延迟上。

系统层还需要处理文件描述符限制。MySQL在高并发下要打开大量文件,默认的1024远远不够,建议调高到65535以上,保险起见可以设到1048576。检查方法就是ulimit -n。至于swap,我不建议把swap当内存兜底,数据库服务器发生swap时,性能会断崖下跌,还不如让内存管理机制直接把进程打死再重启。但完全禁用swap也要谨慎,毕竟操作系统自己有少量内存余量需求,合适做法是设置一个较小的swap值,比如4G~8G,作为极端情况下的缓冲。

2.3 关键配置参数解析

安装前把配置文件的骨架搭好很重要,不然装完再反复重启调参数,时间都浪费了。8.0里我常用的关键参数有这么几个:

  • innodb_buffer_pool_size:默认值只有128M,不调整的话压测完全是另一个量级。建议按上面的内存规划设置。
  • innodb_redo_log_capacity:8.0.30版本以后,redo log从原来的两个固定文件改成了由这个参数统一管理。默认100M,对高写入负载来说偏小,压测时如果发现磁盘写等待高,可以考虑调整到1G~8G。
  • binlog_expire_logs_seconds:默认2592000秒,也就是30天。这个值看业务备份策略来定,不是越大越好。
  • max_connections:默认151,压测前如果并发一上去就连不上,多半是这里撞墙了。
  • innodb_flush_log_at_trx_commit:默认1,代表每次事务提交都把redo log刷到磁盘,数据安全性最高,但延迟也最高。压测时如果目标是看InnoDB引擎自身的极限,可以临时改成2或0,但生产环境不建议动。

还有一个细节:8.0默认会开启X Plugin,监听33060端口,如果你用不到MySQL Shell的X Protocol相关功能,建议在配置里直接关掉,减少不必要的端口暴露面。

3. 一步步完成MySQL 8.0安装

3.1 安装前准备与基础环境

拿到服务器后先做三件事:创建系统用户、确认依赖库、规划目录结构。

先创建mysql系统用户。注意这里要用系统用户且不分配登录shell:

groupadd mysql useradd -r -g mysql -s /bin/false mysql

然后确认libaio库是否安装,8.0初始化阶段依赖这个库,少了会直接报错:

yum install -y libaio # Debian系用 apt install -y libaio

接下来下载官方通用二进制包并解压到目标目录。我的习惯是用/usr/local/mysql作为统一的软链路径,方便后续换版本时切换:

tar -xJf mysql-8.0.XX-linux-glibc2.17-x86_64.tar.xz -C /usr/local/ mv /usr/local/mysql-8.0.XX-linux-glibc2.17-x86_64 /usr/local/mysql

数据目录我一般单独建在业务数据盘上,不跟系统盘混在一起:

mkdir -p /data/mysql/log chown -R mysql:mysql /data/mysql

3.2 配置文件、初始化与启动

先写一个基础版my.cnf。这里给一个我常用的最小骨架:

[mysqld] basedir=/usr/local/mysql datadir=/data/mysql socket=/tmp/mysql.sock pid-file=/data/mysql/mysql.pid log-error=/data/mysql/log/error.log port=3306 character-set-server=utf8mb4 collation-server=utf8mb4_0900_ai_ci server-id=1 log-bin=/data/mysql/log/binlog binlog_expire_logs_seconds=2592000 binlog_format=row innodb_buffer_pool_size=20G innodb_redo_log_capacity=4G max_connections=1000

注意路径和实际规划保持一致,特别是binlog目录要放到独立磁盘上。启动方式我一般先用mysqld_safe做测试,确认没问题后再考虑注册成系统服务。正式环境用systemd管理是更规范的做法,但逻辑上都是一回事。

初始化是8.0和5.7差异比较大的地方。5.7时代可以用mysql_install_db脚本,8.0直接统一用mysqld --initialize:

/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql

初始化完成后,日志末尾会打印一行临时root密码。这个密码只在第一次登录时有效,登录后必须立刻改掉,否则后续操作全都做不了。

启动服务:

/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf &

启动后先确认端口和进程状态:

ss -lntp | grep 3306

如果服务没起来,第一个排查目标是/data/mysql/log/error.log,MySQL几乎所有启动阶段的问题都会写在里面。

3.3 登录验证与安全加固

用临时密码登录:

mysql -uroot -p

登录后立刻改密码:

ALTER USER 'root'@'localhost' IDENTIFIED BY '这里填强密码';

接着创建业务账号并授权。很多初学者习惯直接用root跑业务,这个习惯在8.0里风险更大,因为root权限和系统级权限绑定得更深。建议至少建一个独立账号:

CREATE USER 'app'@'%' IDENTIFIED BY '业务密码'; GRANT ALL PRIVILEGES ON *.* TO 'app'@'%'; FLUSH PRIVILEGES;

验证一下版本和基本读写能力:

SELECT VERSION(); CREATE TABLE test.t(id INT PRIMARY KEY, name VARCHAR(20)); INSERT INTO test.t VALUES (1, 'hello'); SELECT * FROM test.t;

到这里,一个可用的MySQL 8.0实例就起来了。但安装完成只是上半场,对于“安装与基准测试”这个主题,真正有价值的下半场是压测。

4. 基准测试:方法、工具与结果分析

4.1 压测前要明白的三件事

基准测试最核心的价值是建立“能力基线”。我经常跟同事说,没做过压测的数据库,就是一本没有体检报告的账本。系统慢了你不知道是SQL变差了、数据量变大了、还是硬件老化了;做过基线压测,再跑一遍同样脚本,一对比就知道系统整体是否退化。

第一,压测环境要尽量接近生产。如果生产线上的机器和压测机器配置天差地别,压测数字没有任何迁移价值。至少CPU型号、核数、内存、磁盘类型这四个维度要对齐。

第二,每次只改一个变量。今天测buffer pool 16G和20G的差别,其他参数就全部固定。如果你同时改了buffer pool、并发数、binlog策略,得到的结果根本没法归因。

第三,sysbench只是通用负载,不是业务负载。它的oltp_read_write脚本能反映InnoDB在典型OLTP混合读写下的表现,但替代不了针对你核心业务的定制压测。所以我会把它定位成“体检工具”,而不是“业务压测唯一标准”。

4.2 sysbench安装与数据准备

sysbench在主流Linux发行版的基础源里一般都有,直接装:

yum install -y sysbench

验证安装:

sysbench --version

先创建压测用库:

mysql -uroot -p -e "CREATE DATABASE sbtest CHARACTER SET utf8mb4;"

然后执行数据准备。这里我以oltp_read_write.lua脚本为例:

sysbench /usr/share/sysbench/oltp_read_write.lua \ --mysql-host=127.0.0.1 \ --mysql-port=3306 \ --mysql-user=app \ --mysql-password=你的密码 \ --mysql-db=sbtest \ --tables=16 \ --table_size=1000000 \ --threads=16 \ prepare

参数含义不难理解:--tables是表数量,--table_size是每张表的行数,--threads是并发建立数据时的线程数。16张表、每表100万行,合计1600万行,这个数据量能保证压测时InnoDB确实发生真实的磁盘读写和索引维护,而不是全在内存里打转。prepare阶段的时间取决于磁盘性能和表的索引数量,几分钟到十几分钟都正常。

注意一点:sysbench默认会用本地socket连接,我这里显式指定了MySQL的IP和端口,是为了和后面生产环境的形式保持一致。如果连接方式不固定,测出来的网络开销差异会影响结果对比。

4.3 执行压测与输出解读

数据准备完成后,开始正式压测:

sysbench /usr/share/sysbench/oltp_read_write.lua \ --mysql-host=127.0.0.1 \ --mysql-port=3306 \ --mysql-user=app \ --mysql-password=你的密码 \ --mysql-db=sbtest \ --tables=16 \ --table_size=1000000 \ --threads=16 \ --time=300 \ --report-interval=10 \ run

--time=300表示压测持续300秒,--report-interval=10表示每10秒打一次中间结果。压测时间太短(比如30秒)的话,数据还没稳定就结束了,结果随机性很大;300秒是能比较稳定体现系统表现的时间尺度。

跑完后sysbench会输出一份汇总。我最关注的四个指标:

  • transactions:总事务数和每秒事务数,这就是常说的TPS。
  • read/write requests:总请求数和每秒请求数,一般理解为QPS。
  • latency:包含平均延迟、95分位延迟、99分位延迟。
  • 95th percentile:最能反映真实用户体验的延迟指标,它表示95%的请求都在这个延迟以内。

举个例子,假设压测结果TPS是6000,QPS约12万,95分位延迟20ms,这意味着这个实例在20并发下能稳定支撑这么大的吞吐,同时绝大多数查询在20毫秒内返回。如果这个数字对应到业务峰值QPS只有3000,那安全余量是充足的;如果业务峰值已经到1万以上,就得考虑架构调整了。

4.4 把压测结果落回生产决策

建议在压测的时候同时开一个终端观察系统资源:

top # 看CPU、内存、负载 iostat -x 1 # 看磁盘使用率和IO等待

如果压测时CPU使用率接近100%,而磁盘util不高,说明瓶颈在计算层,优化方向是SQL、索引、CPU配置;如果CPU还有大量空闲,但磁盘util已经打满,说明IO层先到瓶颈了,这时候调buffer pool或者优化SQL都是隔靴搔痒。压测结果不是孤立数字,要结合系统指标一起看。

我自己的习惯是拿到一组阶梯并发数据。从1、2、4、8、16、32逐步往上测,每个并发档位跑5分钟,记录TPS和延迟的拐点。这样可以看到系统从“线性扩展”到“瓶颈出现”的临界并发是多少,这个临界点对未来容量规划特别有用。压测结束后用cleanup命令清理数据:

sysbench /usr/share/sysbench/oltp_read_write.lua \ --mysql-host=127.0.0.1 \ --mysql-port=3306 \ --mysql-user=app \ --mysql-password=你的密码 \ --mysql-db=sbtest \ cleanup

5. 实操问题排查速查

5.1 安装阶段常见问题

缺少libaio导致初始化失败。报错信息一般是error while loading shared libraries: libaio.so.1。先把libaio装好再初始化,这事我在新机器上踩过一次,后面每次都会提前装。

初始化时报数据目录不为空。8.0对datadir的初始状态要求很严格,目录里哪怕有个隐藏文件都会拒绝初始化。如果之前试过初始化,把数据目录清干净再重新来过,注意先备份再删。

临时密码找不到。初始化成功后临时root密码会出现在error log里。如果日志里没看到,检查一下是否提前配置了log-error路径,密码只打印一次,之后只能进skip-grant-tables模式去重置,麻烦得多,所以要养成初始化后立刻去日志里截获密码的习惯。

5.2 连接与认证问题

客户端报认证插件不兼容。8.0默认认证插件是caching_sha2_password,老版本的客户端驱动(比如早期PHP扩展、某些老Java驱动)只认识mysql_native_password,握手阶段就会失败。我的建议是优先升级客户端驱动,这才是正路。如果实在没得选,可以把用户改成mysql_native_password,但要知道这意味着安全性下降:

ALTER USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY '密码';

连接数上限。压测时并发一高,客户端报Too many connections,先用show status like 'Threads_connected';确认实际连接数,再判断是要调max_connections,还是业务连接池没用对。这里有个技巧:不要单一调大max_connections,最好同时把处理线程缓存thread_cache_size提上去,避免频繁创建销毁线程。

5.3 压测数据与结果异常

数据不落盘导致结果虚高。如果压测表的数据量远远小于buffer pool容量,所有读都是内存命中,TPS自然高得离谱,但这不代表真实水平。压测时数据量要超过内存能轻松容纳的范围,至少是buffer pool的一到两倍。

压测跑起来后系统直接OOM。大概率是buffer pool设置太大+连接并发太高+操作系统预留不足三者叠加。观察dmesg里的OOM记录,把buffer pool调回合理范围,并发档位从低往高慢慢加,不要一上来就满负荷跑。

压测结果波动极大。先看是不是有别的进程在抢CPU或磁盘,比如备份、日志清理。压测之前一定要确认系统处于稳定状态,关掉不必要的定时任务,否则数据没法看。

5.4 参数修改不生效

SET GLOBAL之后连接还是旧值。8.0的动态参数有些全局生效,但对已有连接不生效,只有新连接才会拿到新值。压测脚本要重连一次,或者在压测时统一用新连接池。另外有个高频误区是改了my.cnf不重启就以为生效了。对于my.cnf里的静态参数,必须重启实例;对于动态参数,可以先用SET GLOBAL验证,确认没问题后再写进配置文件,防止重启后回滚。

6. 最后说几句实在话

安装这件事,照着步骤来其实不难,真正拉开差距的是规划。我见过太多人一上来就装,装上发现buffer pool还是128M,日志和数据混在一块盘上,压测数据一出来完全没法看,回头又要推倒重来。所以这篇东西里面,比重最大的其实是第2章的规划和第4章的压测方法,步骤只是载体。

还有一点想提醒:压测基线要建档。把环境配置、内核参数、MySQL参数、sysbench命令版本、结果数字都存在一个地方,每条记录都写上测试日期和变更了什么。下次系统出问题,或者你调了参数想验证效果,跑一遍同样的脚本一比就知道有没有变化。这个习惯帮我省过很多次排查的时间,属于成本极低、收益极高的实操。

我个人做数据库运维这些年,最深的一点感受是:不要迷信某个版本,也不要迷信某个压测数字。版本只是一个工具,压测数字只是系统在一定条件下的快照。真正值钱的是你对自己这套系统的理解——哪些参数敏感,哪些操作会带来风险,哪些指标能反映健康度。搞清楚了这些,MySQL 8.0的安装与基准测试就只是一次系统认识的开始,而不是结束。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询