MySQL 8.4 把一个默认值改成了 O_DIRECT。读写都绕过操作系统的页缓存。而配套的那个参数,默认值两版都没动,还是 128 MB。

装完 MySQL 8.4,服务正常启动。SHOW VARIABLES 一切正常,监控也没什么异常。但读性能可能比 8.0 还差。而且是那种看起来没坏、就是慢的很。

原因不是配置写错了。是 8.4 改了 innodb_flush_method 的默认值,而它牵连的那个参数没跟着改。

好在要改的只有一个参数。这篇讲三件事:为什么是它、该改多少、怎么验证生效。

机器是云服务器,4 核 8G,跟 Web 服务共用一台。数据库是 MySQL 8.4.11,容器镜像 mysql:8.4.11。部署走 1Panel 容器化,端口只映射到 127.0.0.1:3306,不暴露公网。同机还跑着 OpenResty 容器、PHP-FPM 容器和 1Panel 面板。

命令里用变量代替容器名,先在终端执行一次:

# 换成你在 1Panel 里给 MySQL 起的名字(= 容器名)
export MYSQL_CTN="mysql84"

回显来源说明一下。标「实测」的来自这次部署,2026-09-16。原始数值原样保留,只把表格边框排整齐。标「官方」的是 MySQL 官方文档、官方 Bug 系统、Oracle 官方博客的原文,出处随文标注。

为什么是 8.4,不是 8.0

选版本没什么可纠结。MySQL 8.0 的社区版支持已经在 2026 年 4 月 30 日结束。8.4 是 MySQL 的第一个 LTS 版本,官方生命周期排到 2029 年,扩展支持至 2032 年。

8.0 已经不是能用就行的问题。停止支持意味着安全补丁不再下发。新装环境没有理由选它。

但升级到 8.4 有个代价,藏在默认值里。

两个官方事实,拼出变慢的因果链

事实一。8.4 把 innodb_flush_method 的默认值改成了 O_DIRECT。

这条在 MySQL 官方 Bug 系统里有白纸黑字的结论。用户提了 Bug #117691,标题直译过来是「MySQL 8.4 和 9 没有利用 Linux 页缓存,与 8.0 相反」。开发者的官方答复是:

The default value of innodb_flush_method is changed to O_DIRECT in 8.4+
to benefit production servers running with large buffer pool. If users want to use a
small buffer pool, they may explicitly configure the innodb_flush_method to fsync.
… Thus, this is not a bug but an expected change in behavior.

翻译成一句话。8.4 假设你会给一个大 buffer pool,所以把绕开 OS 缓存设成了默认。官方给出的处方是两条路。要么把 buffer pool 给够,要么显式改回 fsync。

配套的默认值变化还有一批,官方文档和 Percona 的 8.4 默认值对照表均列明。innodb_flush_method 在 Linux 上从 fsync 变成 O_DIRECT,不支持时回落 fsync。innodb_io_capacity 从 200 变成 10000。innodb_log_buffer_size 从 16 MB 变成 64 MB。innodb_adaptive_hash_index 从 ON 变成 OFF。innodb_change_buffering 从 all 变成 none。

8.4 的整体方向是开箱即生产。但有一个关键参数除外。

事实二。innodb_buffer_pool_size 的默认值,两版都是 128 MB。

Oracle 官方博客《Auto Adapting Configuration Parameters in MySQL》原文:

The default values are maintained for innodb_buffer_pool_size at 128 MB
and innodb_redo_log_capacity at 1 GB in both MySQL 8.0 and MySQL 8.4.

两个事实拼起来:

没给:默认仍是 128MB

给够:本案 2G

升级到 MySQL 8.4

innodb_flush_method 默认值
fsync 变 O_DIRECT

数据文件读写绕过 OS 页缓存

innodb_buffer_pool_size
给够了吗?

没有任何缓存兜底
读性能比 8.0 更差

热数据全在 buffer pool
性能达到预期

在 8.0 上,fsync 走 OS 页缓存。即使 buffer pool 给得小,热点数据还能被操作系统的空闲内存兜一层,于是也能跑。

到 8.4,O_DIRECT 把这一层撤了。读数据文件也绕开页缓存,缓存职责全部落回 buffer pool。而此时 buffer pool 还是 128 MB。

兜底的那一层没了,新的那一层没建起来。

这就是升级后反而变慢的完整因果链。它不是 bug。是默认值的组合效应。

这一个参数,该给多少

官方给了一个自动档,这台机器用不了

Oracle 官方博客里提供了一个省事方案。打开 innodb_dedicated_server,让 InnoDB 自己算:

You can now move the MySQL server to production using the default configuration
by simply setting these two variables: max_connections = N and innodb_dedicated_server = ON

它的算法,官方原文。innodb_buffer_pool_size:可用物理内存 M 小于 1 GB 时给 128 MB。1 GB 到 4 GB 之间给 M × 0.50。大于 4 GB 时给 M × 0.75。innodb_redo_log_capacity:逻辑 CPU 数除以 2 GB,上限 16 GB。

把 4 核 8G 代进去算一遍。buffer pool 6.00 GB,redo 2.0 GB,合计 8.00 GB。正好等于整机内存。连操作系统都没地方待,更别提同一台机器上还跑着 OpenResty、PHP-FPM 和 1Panel 面板。

另外两种配置也列一下。4 核 16 GB 算出来是 12.00 GB 加 2.0 GB,合计 14.00 GB。8 核 16 GB 是 12.00 GB 加 4.0 GB,合计 16.00 GB。

为什么算得这么激进?因为 innodb_dedicated_server 的语义是这台机器专供 MySQL。dedicated 就是专用的意思。而我们这台是共用机器。

结论是:共用一台机器的场景,这个自动档不能用,必须手动算。

手动算,从整机内存倒着分

算账的顺序是先扣掉别人,剩下的才归 MySQL。

innodb_buffer_pool_size 给 2.0 GB。innodb_redo_log_capacity 给 1.0 GB。MySQL 自身加连接加排序缓冲,估 0.5 GB。OpenResty 加面板加系统,估 1.0 GB。PHP-FPM 按 10 个子进程、每个 60 到 80 MB 算,0.8 GB。

合计 5.3 GB。8 GB 减掉合计,余量 2.7 GB。

留这 2.7 GB 的意义是:流量高峰时 PHP-FPM 子进程会涨,缓冲区、连接数都会涨。这块是安全垫。

所以这台机器给 innodb_buffer_pool_size = 2G。如果你的是 4 核 8G 且只跑 MySQL,可以给到 4G 到 5G。如果是共用,2G 是稳妥的起点。上线后看 innodb_buffer_pool_read_requests 与磁盘读的比例再调。

改法与验证

配置写在 1Panel 的 MySQL 配置文件里。路径是 /opt/1panel/apps/mysql/<应用名>/conf/my.cnf。

[mysqld]
# ---------- 内存(适配 4核8G)----------
innodb_buffer_pool_size   = 2G          # ← 唯一必须改的一个:8.4 绕过 OS 缓存,靠这里兜住热点数据
innodb_redo_log_capacity  = 1G          # 8.4 默认值,写出来只是显式记录
innodb_log_buffer_size    = 64M         # 8.4 默认值(8.0 是 16M),写出来只是显式记录
innodb_flush_method       = O_DIRECT    # 8.4 默认值,写出来只是显式记录

# ---------- 连接 ----------
max_connections           = 200

# ---------- 字符集 ----------
character-set-server      = utf8mb4
collation-server          = utf8mb4_unicode_ci

# ---------- 时区 ----------
default-time-zone         = '+08:00'

# ---------- 慢查询 ----------
slow_query_log            = ON
long_query_time           = 2

注意注释里那句话。上面四项内存参数里,后三项都是 8.4 的默认值。写出来只是为了让配置自解释,改不改行为一样。真正影响性能的只有第一项。

这也是这篇标题的由来。8.4 已经把一批默认值调成生产可用了,你不用逐条照抄 8.0 时代的老教程。唯独 innodb_buffer_pool_size 必须自己给。

改完重启容器,然后验证:

docker restart "$MYSQL_CTN"
# 进容器用 mysql 客户端核验(密码换成你自己的)
docker exec -i "$MYSQL_CTN" mysql -uroot -p'<你的密码>' -e "
  SELECT VERSION();
  SHOW VARIABLES WHERE Variable_name IN
    ('innodb_buffer_pool_size', 'innodb_flush_method');
"

回显(2026-09-16 实测):

+-----------+
| VERSION() |
+-----------+
| 8.4.11    |
+-----------+

+-------------------------+------------+
| Variable_name           | Value      |
+-------------------------+------------+
| innodb_buffer_pool_size | 2147483648 |
| innodb_flush_method     | O_DIRECT   |
+-------------------------+------------+

2147483648 就是 2 GB,2 × 1024³。参数值不要靠肉眼估,看回显里的字节数。写 2G 得到的是这个数,写 2048M 也是这个数,写 2000M 就不是了。

我当时看 SHOW VARIABLES,一项都没异常。我以为装完就能用,服务也确实起来了。会出问题的地方在读,不在启动这一层。

顺手要处理的,跟性能无关但不改会出事

这几个参数跟性能无关,属于不改迟早出事故的类型。

排序规则。utf8mb4_0900_ai_ci 的陷阱

8.4 的 utf8mb4 默认 collation 是 utf8mb4_0900_ai_ci。而项目里所有 SQL 脚本、表定义、连接串用的都是 utf8mb4_unicode_ci。

两者混用会在 JOIN、比较、子查询时报错:

Illegal mix of collations (utf8mb4_0900_ai_ci,IMPLICIT) and (utf8mb4_unicode_ci,IMPLICIT) for operation '='

建库时必须显式选 utf8mb4_unicode_ci。留空就会拿到 8.4 的默认值。服务端也一并锁死:

character-set-server      = utf8mb4
collation-server          = utf8mb4_unicode_ci

认证插件。老客户端连不上

8.4 默认禁用了 mysql_native_password,全面转向 caching_sha2_password。这一点官方升级文档里有明确说明。

后果是老版本客户端连不上。比如 Navicat 11 及更早版本就不支持 caching_sha2_password。解决方式是升级客户端,Navicat 16+ 或 DBeaver,而不是把认证插件改回去。

时区与慢查询

default-time-zone         = '+08:00'
slow_query_log            = ON
long_query_time           = 2

时区这条要和 PHP 侧的 date.timezone 对上,本案是 Asia/Shanghai。否则入库时间和取出时间会差 8 小时。这类问题排查起来非常费时。

慢查询日志建议建库时就开。long_query_time = 2 表示超过 2 秒的语句落盘。新站流量小,但它记录的是未来某一天突然变慢的第一手证据。

这台机器上 2G 是起点。到底够不够,得看上线后 innodb_buffer_pool_read_requests 和磁盘读的比例。这个数我还没跑出来,等待后续补充。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐