MySQL 性能分析报告:Page Cache 与 fsync 对读写性能的影响

1. 实验概述

1.1 实验目的

  • 验证 Linux Page Cache 对文件读写的缓存机制
  • 量化 Page Cache 清空(drop_caches)对系统缓存的影响
  • 通过 strace 追踪 MySQL 在 OLTP 压测下的 fsync/fdatasync 调用频率
  • 分析 innodb_flush_method 配置(fsync vs O_DIRECT)对 I/O 路径的影响

1.2 实验环境

项目 详情
操作系统 Ubuntu 22.04.3 LTS
内核版本 Linux 5.15.0-76-generic
内存 7.8 GiB
MySQL 版本 8.0.x
压测工具 sysbench 1.0.20
追踪工具 strace
测试库 sbtest(4 张表 × 100,000 行)

1.3 当前实验配置

参数 当前值 说明
innodb_flush_method O_DIRECT 数据文件绕过 Page Cache
innodb_flush_log_at_trx_commit 1(双 1) 每次事务提交刷 Redo Log
sync_binlog 1(双 1) 每次事务提交刷 Binlog
innodb_buffer_pool_size 4GB 数据页缓存

2. Page Cache 基础实验

2.1 实验步骤

bash 复制代码
# 1. 采集基准状态
echo "=== 基准状态 (dd 之前) ===" >> /tmp/pagecache_experiment.log
date >> /tmp/pagecache_experiment.log
cat /proc/meminfo | grep -E "Cached|Dirty|Writeback" >> /tmp/pagecache_experiment.log
free -h >> /tmp/pagecache_experiment.log

# 2. 生成 1GB 测试文件
dd if=/dev/zero of=/tmp/test bs=1M count=1024

# 3. 观察 Page Cache 变化
echo "=== dd 写入 1GB 后 ===" >> /tmp/pagecache_experiment.log
date >> /tmp/pagecache_experiment.log
cat /proc/meminfo | grep -E "Cached|Dirty|Writeback" >> /tmp/pagecache_experiment.log
free -h >> /tmp/pagecache_experiment.log

# 4. 清空 Page Cache(仅测试环境)
sync
echo 3 > /proc/sys/vm/drop_caches

# 5. 观察清空后的状态
echo "=== drop_caches 后 ===" >> /tmp/pagecache_experiment.log
date >> /tmp/pagecache_experiment.log
cat /proc/meminfo | grep -E "Cached|Dirty|Writeback" >> /tmp/pagecache_experiment.log
free -h >> /tmp/pagecache_experiment.log

2.2 三次采集数据对比

指标 基准状态(dd 前) dd 写入 1GB 后 drop_caches 后 变化分析
Cached 1,266,044 kB (~1.21 GB) 2,315,008 kB (~2.21 GB) 355,576 kB (~347 MB) dd 后缓存增加约 1.0 GB;drop_caches 后剩余 347 MB 为系统进程活跃缓存
Dirty 108 kB 56 kB 28 kB 脏页始终保持在极低水平,内核刷脏线程响应迅速
Writeback 0 kB 0 kB 0 kB 无积压回写操作
MemFree 5.0 GiB 4.0 GiB 6.2 GiB 写入时 1GB 被缓存占用;清空后缓存释放
MemAvailable 6.2 GiB 6.2 GiB 6.2 GiB 系统可用内存估算值未发生明显变化

基准状态(dd 前)完整输出:

text 复制代码
Cached:          1266044 kB
Dirty:               108 kB
Writeback:             0 kB
Mem:           7.8Gi       1.2Gi       5.0Gi        90Mi       1.5Gi       6.2Gi

dd 写入 1GB 后完整输出:

text 复制代码
Cached:          2315008 kB
Dirty:                56 kB
Writeback:             0 kB
Mem:           7.8Gi       1.2Gi       4.0Gi        90Mi       2.5Gi       6.2Gi

drop_caches 后完整输出:

text 复制代码
Cached:           355576 kB
Dirty:                28 kB
Writeback:             0 kB
Mem:           7.8Gi       1.2Gi       6.2Gi        90Mi       402Mi       6.2Gi

2.3 实验结论

  1. Page Cache 自动缓存写入数据: 1GB 文件写入后,Cached 从 1.21GB 增长到 2.21GB,增加了约 1GB,验证了"写入先入缓存"的机制。
  2. 脏页刷写非常积极: Dirty 始终保持在 KB 级别(108KB → 56KB → 28KB),说明内核刷脏线程响应迅速。
  3. drop_caches 释放的是可回收缓存: 清空后剩余的 347MB 是 MySQL、sshd、systemd 等进程正在使用的文件页,内核不会强制回收。
  4. drop_caches 仅在测试环境可用: 生产环境执行此操作会使所有文件缓存失效,导致性能急剧下降。

3. Sysbench 压测结果

3.1 压测命令

bash 复制代码
# 安装
apt-get update && apt-get install -y sysbench

# 创建 sbtest 库
mysql -e "CREATE DATABASE IF NOT EXISTS sbtest;"

#  准备 4 张表,每张表 10 万行数据(数据量越大,压测效果越明显)
sysbench oltp_read_write \
--mysql-host=127.0.0.1 \
  --mysql-user='app_user' \
  --mysql-password='MySecurePass123!' \
--mysql-db=sbtest \
--tables=4 \
--table-size=100000 \
prepare


sysbench oltp_read_write \
  --mysql-host=127.0.0.1 \
  --mysql-user='app_user' \
  --mysql-password='MySecurePass123!' \
  --mysql-db=sbtest \
  --tables=4 \
  --table-size=100000 \
  --time=60 \
  --threads=16 \
  run

3.2 压测结果

text 复制代码
SQL statistics:
    queries performed:
        read:                            634200
        write:                           181200
        other:                           90600
        total:                           906000
    transactions:                        45300  (754.77 per sec.)
    queries:                             906000 (15095.36 per sec.)

General statistics:
    total time:                          60.0168s
    total number of events:              45300

Latency (ms):
         min:                                    4.93
         avg:                                   21.19
         max:                                   94.72
         95th percentile:                       42.61
         sum:                               960041.29

Threads fairness:
    events (avg/stddev):           2831.2500/17.46
    execution time (avg/stddev):   60.0026/0.01

3.3 压测结果解读

指标 数值 说明
TPS 754.77 每秒处理 754 个事务
QPS 15095.36 每秒处理约 1.5 万次查询
平均延迟 21.19 ms 事务平均响应时间
95% 延迟 42.61 ms 95% 的事务在 42.61ms 内完成
总事务数 45,300 60 秒内共完成 4.5 万事务

4. strace 追踪 fsync 调用

4.1 追踪命令

bash 复制代码
timeout 20 strace -f -y -e trace=fsync,fdatasync \
  -p $(pgrep -x mysqld | head -1) -o /tmp/mysql_strace_20s.log

-y 参数使 strace 自动显示每个文件描述符对应的完整路径。

4.2 调用频率统计

bash 复制代码
root@mysql-02:~# echo "fsync: $(grep -c 'fsync' /tmp/mysql_strace_20s.log)  fdatasync: $(grep -c 'fdatasync' /tmp/mysql_strace_20s.log)"
fsync: 24461  fdatasync: 6419
系统调用 20 秒调用次数 平均每秒调用次数
fsync 24,461 ~1,223 次/秒
fdatasync 6,419 ~321 次/秒
合计 30,880 ~1,544 次/秒

4.3 数据验证

理论推算:

在 MySQL 双 1 配置下,每个事务提交需要触发 2 次同步刷盘:

  • Redo Log:fsync
  • Binlog:fdatasync
bash 复制代码
理论每秒 fsync 需求 = TPS × 2 = 754.77 × 2 ≈ 1,509 次/秒
20 秒理论总数 ≈ 1,509 × 20 ≈ 30,180 次

strace 实测 30,880 次 vs 理论推算 30,180 次,偏差约 2.3%,两者基本吻合。

fsyncfdatasync 的比例约为 24,461 : 6,419 ≈ 3.8 : 1,说明 Redo Log 的刷盘频率高于 Binlog。

4.4 典型 strace 输出

bash 复制代码
3486710 fsync(15</data/mysql/ib_logfile1>) = 0
3486710 fsync(15</data/mysql/ib_logfile1>) = 0
3486696 fdatasync(22</data/mysql/binlog.000003>) = 0
3486696 fsync(10</data/mysql/ib_logfile0>) = 0
3486702 fsync(17</data/mysql/ib_logfile2>) = 0

通过 -y 参数,可以直接看到:

  • ib_logfile0 / ib_logfile1 / ib_logfile2 → InnoDB redo log
  • binlog.000003 → MySQL binary log
  • = 0 → 系统调用成功完成

5. innodb_flush_method 配置对 I/O 路径的影响

5.1 两种配置的本质区别

innodb_flush_method 控制 InnoDB 数据文件(.ibd) 的打开方式,不直接影响 Redo Log 和 Binlog。

配置 数据文件打开方式 是否经过 Page Cache 是否调用 fsync
fsync open()+ fsync() 经过 Page Cache ✅ 是
O_DIRECT open(O_DIRECT) 绕过 Page Cache ✅ 是(仍需要)

Redo Log 和 Binlog 的 I/O 路径不受 innodb_flush_method 影响 ,始终经过 Page Cache + fsync

⚠️注意:不要误以为设置 O_DIRECT = 绕过 Page Cache = 不需要 fsync()。实际上 O_DIRECT 只是绕过了操作系统的 Page Cache,但数据仍然可能停留在磁盘设备的写缓存中 ,同时文件系统元数据也可能还在缓存中。fsync() 的作用正是强制刷新这两者,确保数据真正持久化到物理介质。所以即使配置了 O_DIRECTfsync() 依然是 InnoDB 确保持久性的必要步骤。这也是为什么你在 strace 日志中始终能看到大量 fsync 调用的原因。

5.2 两种配置下的完整 I/O 路径

配置一:innodb_flush_method = fsync
text 复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                          fsync 模式 I/O 路径                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  读路径(数据文件 .ibd):                                                  │
│  应用 → Buffer Pool → (未命中) → read() → Page Cache ←→ 磁盘              │
│                                                                             │
│  写路径(数据文件 .ibd):                                                  │
│  应用 → Buffer Pool → (脏页) → write() → Page Cache → (异步) → 磁盘       │
│                                                                             │
│  写路径(Redo Log):                                                       │
│  Log Buffer → write() → Page Cache → fsync() ────→ 磁盘                   │
│                                                                             │
│  写路径(Binlog):                                                         │
│  Binlog Buffer → write() → Page Cache → fdatasync() ──→ 磁盘              │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

特点:

  • 数据文件读写都经过 Page Cache
  • Page Cache 会缓存数据文件,但同时也存在"双缓冲"(Buffer Pool + Page Cache)
  • 刷脏页时可能产生性能抖动
配置二:innodb_flush_method = O_DIRECT(当前实验配置)
text 复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                          fsync 模式 I/O 路径                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  读路径(数据文件 .ibd):                                                  │
│  应用 → Buffer Pool → (未命中) → read() → Page Cache ←→ 磁盘              │
│                                                                             │
│  写路径(数据文件 .ibd):                                                  │
│  应用 → Buffer Pool → (脏页) → write() → Page Cache → (异步) → 磁盘       │
│                                                                             │
│  写路径(Redo Log):                                                       │
│  Log Buffer → write() → Page Cache → fsync() ────→ 磁盘                   │
│                                                                             │
│  写路径(Binlog):                                                         │
│  Binlog Buffer → write() → Page Cache → fdatasync() ──→ 磁盘              │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

特点:

  • 数据文件绕过 Page Cache,直接读写磁盘
  • 消除了"双缓冲",节省内存
  • Buffer Pool 成为数据文件唯一的缓存层
  • 数据文件的读性能完全依赖 Buffer Pool 大小

5.3 对本实验 strace 日志的影响

O_DIRECT 模式下,strace 日志中依然能看到大量 fsync,原因是:

文件类型 是否走 Page Cache strace 中是否出现 fsync 原因
数据文件(.ibd) 绕过 Page Cache 是(少量) 刷脏页时调用 fsync()确保落盘
Redo Log 走 Page Cache 是(高频) 双 1 配置下每事务 fsync()
Binlog 走 Page Cache 是(高频) 双 1 配置下每事务 fdatasync()

实测数据也印证了这一点: 20 秒内 30,880 次 fsync + fdatasync,对应 754 TPS × 2 × 20 ≈ 30,180 次的理论值。这些 fsync 主要来自 Redo Log 和 Binlog,与 innodb_flush_method 无关。

5.4 fsync vs O_DIRECT 的优缺点对比

对比维度 fsync(经过 Page Cache) O_DIRECT(绕过 Page Cache)
读缓存 Page Cache + Buffer Pool 双重缓存 仅 Buffer Pool
内存占用 较高(双缓存) 较低(单一缓存)
写性能 异步刷脏,峰值写入快 同步写入,写入路径更直接
性能抖动 刷脏页时可能产生抖动 抖动较小,更稳定
缓存回收 依赖内核 Page Cache 回收机制 Buffer Pool 独立管理
适用场景 内存充足、读写混合负载 内存有限、追求稳定延迟

5.5 对 Page Cache 观测的影响

设置 O_DIRECT 后,MySQL 数据文件不再占用 Page Cache。这意味着:

  1. /proc/meminfo 中的 Cached 值不包含 MySQL 数据文件缓存 ,只包含其他文件(如日志、系统文件、/tmp 测试文件等)。
  2. 本实验的 Page Cache 基础实验中dd 写入 /tmp/testdrop_caches 的操作反映的是 /tmp 文件系统的 Page Cache,不是 MySQL 数据文件的 Page Cache。
  3. 如果在 fsync 模式下做同样的实验 ,MySQL 数据文件也会占用 Page Cache,Cached 值会更高,drop_caches 对 MySQL 读性能的冲击也会更大。

6. 结论

6.1 Page Cache 对 MySQL 读性能的影响

Page Cache 是否为 MySQL 提供读缓存保护,取决于 innodb_flush_method 配置:

配置 数据文件读路径 读缓存来源
fsync 经过 Page Cache Buffer Pool + Page Cache
O_DIRECT 绕过 Page Cache 仅 Buffer Pool

O_DIRECT 模式下,MySQL 数据文件不再依赖 Page Cache,读性能完全取决于 Buffer Pool 的命中率。

6.2 Page Cache 对 MySQL 写性能的影响

无论 innodb_flush_method 如何配置:

  • Redo Log 和 Binlog 始终经过 Page Cache + fsync
  • 事务提交的 fsync 绕不开 Page Cache 的刷盘机制
  • Page Cache 无法加速 fsync

O_DIRECT 将数据文件的写入从"异步刷脏"变为"直接落盘",减少了 Page Cache 刷脏带来的性能抖动,但并未消除事务提交的 fsync 瓶颈

6.3 核心发现

  1. 本次实验 TPS 754.77 :对应约 1,509 次/秒的 fsync 需求,strace 实测约 1,544 次/秒,完全吻合。
  2. innodb_flush_method = O_DIRECT 只影响数据文件 :Redo Log 和 Binlog 的 I/O 路径不变,fsync 压力依然来自日志刷盘。
  3. 两种配置的核心差异:
    • fsync:数据文件经过 Page Cache,双缓存,内存占用高
    • O_DIRECT:数据文件绕过 Page Cache,单缓存,内存占用低

6.4 优化建议

方向 措施 说明
已启用 innodb_flush_method = O_DIRECT ✅ 当前已配置,减少了双缓存开销
硬件升级 更换高 IOPS、低延迟磁盘(NVMe SSD) 降低 fsync 延迟,提升 TPS
参数调优 innodb_flush_log_at_trx_commit=2 减少 fsync等待,但可能丢失 1 秒数据
参数调优 sync_binlog=0>1 减少 binlog 刷盘频率
参数调优 innodb_use_fdatasync=ON(MySQL 8.0+) 减少不必要的元数据刷新
参数调优 增大 innodb_log_file_size 减少日志切换频率
参数调优 调大 binlog_group_commit_sync_delay 合并多个事务的 fsync请求
text 复制代码
参数可以修改为:Sync_binlog=100 / innodb_flush_log_at_trx_commit=2(确保机器不会宕机掉电的情况下可以更改,提高速度)
Sync_binlog=100 / innodb_flush_log_at_trx_commit=2 此场景不会丢失数据(机器未宕机不丢)

innodb_flush_log_at_trx_commit = 0 一秒一次落盘,不写操作系统内存
innodb_flush_log_at_trx_commit = 2 写到操作系统,一秒刷一次盘

Sync_binlog = 100   100 次进行一次刷盘
Sync_binlog = 0 写到cache 中,操作系统决定什么时候刷

附录 A:实验命令速查

bash 复制代码
# 1. Page Cache 状态查看
cat /proc/meminfo | grep -E "Cached|Dirty|Writeback"
free -h

# 2. 写入测试文件
dd if=/dev/zero of=/tmp/test bs=1M count=1024

# 3. 清空 Page Cache(仅测试环境)
sync && echo 3 > /proc/sys/vm/drop_caches

# 4. Sysbench 压测
sysbench oltp_read_write \
  --mysql-host=127.0.0.1 \
  --mysql-user='app_user' \
  --mysql-password='MySecurePass123!' \
  --mysql-db=sbtest \
  --tables=4 \
  --table-size=100000 \
  --time=60 \
  --threads=16 \
  run

# 5. strace 追踪 MySQL fsync(带路径解析)
timeout 20 strace -f -y -e trace=fsync,fdatasync \
  -p $(pgrep -x mysqld | head -1) -o /tmp/mysql_strace_20s.log

# 6. 统计 fsync 调用次数
echo "fsync: $(grep -c 'fsync' /tmp/mysql_strace_20s.log)  fdatasync: $(grep -c 'fdatasync' /tmp/mysql_strace_20s.log)"

# 7. 查看当前配置
mysql -e "SHOW VARIABLES LIKE 'innodb_flush_method';"
mysql -e "SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';"
mysql -e "SHOW VARIABLES LIKE 'sync_binlog';"

附录 B:配置对比速查表

文件类型 是否经过 Page Cache 是否调用 fsync 控制参数
数据文件(.ibd) fsync模式:是 O_DIRECT模式:否 innodb_flush_method
Redo Log(ib_logfile)* (两种模式都走) innodb_flush_log_at_trx_commit
Binlog(binlog.*) (两种模式都走) sync_binlog

关键结论:innodb_flush_method 只控制数据文件的 I/O 路径,Redo Log 和 Binlog 的刷盘行为不受其影响。这也是为什么无论设置为 fsync 还是 O_DIRECT,strace 中都会看到大量 fsync 调用的根本原因。

实验解决的问题方向

场景一:业务高峰期 MySQL 响应变慢,CPU 和内存都正常

现象:

  • 应用报错"连接超时"或"查询超时"
  • top 看 CPU 不高,内存有剩余
  • 业务侧反馈"数据库好慢"

排查步骤:

base 复制代码
# 第一步:先看磁盘是不是瓶颈
iostat -dx 1

# 如果看到 %util 持续 80%~100%,说明磁盘在满负荷工作
# 看到 w_await 或 r_await 超过 10ms,说明磁盘响应慢

对照实验结论:

  • 实验里 iostat 显示 %util=100%,同时 strace 显示每秒 1500+ 次 fsync
  • 这说明:磁盘的写能力已经被 MySQL 的日志刷盘占满
  • 此时,Buffer Pool 再大也救不了 ,因为瓶颈在磁盘的 fsync 延迟上

快速定位命令:

bash 复制代码
# 1. 确认是不是双1配置导致刷盘太频繁
mysql -e "SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';"
mysql -e "SHOW VARIABLES LIKE 'sync_binlog';"

# 如果都是 1,说明每笔事务都在等 fsync 返回

# 2. 看当前有多少脏页积压
cat /proc/meminfo | grep Dirty

# 如果 Dirty 持续增长到 GB 级别,说明刷脏页跟不上写入速度,应用随时可能被阻塞

判断结论:

如果 %util 高、Dirty 持续增长,说明磁盘 IOPS 已经到天花板了。实验已经证明:当 TPS 达到 754 时,磁盘 fsync 需求是 1500 次/秒。线上如果 TPS 接近这个值,磁盘就是瓶颈。解决办法只有两个:换更好的磁盘,或者调整刷盘策略(牺牲一部分持久性换性能)。

场景二:MySQL 突然变慢,尤其是查询变慢

现象:

  • 平时正常的查询现在要好几秒
  • iostat 看磁盘 %util 并不高

排查步骤:

bash 复制代码
# 1. 先看 Page Cache 是不是被清空了
cat /proc/meminfo | grep Cached

# 2. 如果是突然下降了一大截,可能是有人执行了 drop_caches 或系统内存紧张导致内核回收了大量缓存

对照实验结论:

实验里 drop_caches 后,Cached 从 2.21GB 掉到了 347MB。如果线上是 fsync 模式(数据文件走 Page Cache),这 1.8GB 缓存没了,意味着大量数据页要从磁盘重新读,查询自然变慢。

快速定位命令:

bash 复制代码
# 1. 确认当前 innodb_flush_method
mysql -e "SHOW VARIABLES LIKE 'innodb_flush_method';"

# 如果 = fsync,数据文件依赖 Page Cache,drop_caches 或内存紧张会严重拖累性能
# 如果 = O_DIRECT,数据文件不依赖 Page Cache,突然变慢的原因在别处

# 2. 查看系统日志,确认是否有人执行了 drop_caches
grep -i "drop_caches" /var/log/syslog

# 3. 查看是否有大量内存回收(kswapd 活动)
dmesg | tail -100 | grep -i "out of memory\|oom\|kswapd"

判断结论:

如果 innodb_flush_method = fsync,查询突然变慢 → 优先检查 Page Cache 是不是被清空了。如果 = O_DIRECT,查询变慢 → 优先检查 Buffer Pool 命中率(SHOW ENGINE INNODB STATUSBuffer pool hit rate = Database pages / Buffer pool size),因为 O_DIRECT 下数据文件完全依赖 Buffer Pool,Page Cache 不兜底。

场景三:主从复制延迟突然增大

现象:

  • SHOW SLAVE STATUS 看到 Seconds_Behind_Master 持续增长
  • 从库磁盘利用率很高

排查步骤:

bash 复制代码
# 1. 从库上执行
iostat -dx 1
cat /proc/meminfo | grep Dirty

# 2. strace 跟踪从库 SQL 线程
## ⚠️ 注意:线上生产环境,不要直接用 strace -p $(pidof mysqld) 挂上去。
## strace 会捕获所有系统调用,MySQL 在高并发下每秒几万次调用,输出量巨大
## strace 自身的处理开销会使 MySQL 性能进一步恶化(延迟可能翻倍)
## 可能把磁盘写满(日志文件暴增)

strace -f -y -e trace=fsync,fdatasync -p $(pgrep -x mysqld | head -1) -c

# 生产环境 安全一些的做法
# 方法一:只抓 5 秒,立即停止
timeout 5 strace -f -y -e trace=fsync,fdatasync -p $(pidof mysqld) -o /tmp/strace_quick.log

# 方法二:只统计不输出详情(损耗最小)
strace -f -c -e trace=fsync,fdatasync -p $(pidof mysqld) -o /dev/null &
# 跑 10 秒后 kill 掉,看汇总

# 最安全的办法是 使用 
SHOW GLOBAL STATUS LIKE 'Innodb_log_writes'
SHOW GLOBAL STATUS LIKE 'Innodb_data_fsyncs'
pidstat -d
iostat -x 
# 命令查看 具体的情况

对照实验结论:

从库的 SQL 线程在回放 binlog 时,每执行一个事务也要刷 Redo Log 和 Binlog(如果从库也开了双 1)。实验证明 754 TPS = 1500 次 fsync/秒,从库如果磁盘性能不如主库,回放速度就会跟不上主库的写入速度。

快速定位命令:

bash 复制代码
# 1. 看从库的磁盘性能
fio --name=iops-test --filename=/dev/vda --direct=1 --rw=randrw --bs=4k --numjobs=4 --size=1G --runtime=30

# 2. 对比主从的磁盘 IOPS 能力
# 如果从库 IOPS 低于主库,延迟会持续累积

判断结论:

主从延迟往往不是网络问题,而是从库磁盘刷盘能力跟不上主库。你实验里 754 TPS 就已经把磁盘跑满了,如果从库磁盘性能一样,TPS 超过 700 就开始累积延迟。

场景四:内存使用率很高,"buff/cache" 占了大量内存

现象:

  • free -h 看到 buff/cache 占了 5~6GB
  • 担心内存不够用

排查步骤:

bash 复制代码
# 1. 先看配置
mysql -e "SHOW VARIABLES LIKE 'innodb_flush_method';"

# 2. 看 Page Cache 里主要是什么
# 用 fincore 或直接看 /proc/meminfo
cat /proc/meminfo | grep -E "Cached|Dirty|Writeback"

对照实验结论:

实验里 Cached 从 1.21GB 涨到 2.21GB 是 /tmp/test 导致的,但线上你看到的 buff/cache 可能包含:

  • MySQL 数据文件(如果 flush_method=fsync
  • MySQL 日志文件(Redo Log + Binlog 始终走 Page Cache)
  • 其他系统文件

判断结论:

buff/cache不一定是坏事 ,反而是 Linux 利用空闲内存加速 I/O 的正常行为。实验里 drop_cachesavailable 还是 6.2GB,说明内核认为这些缓存可以被回收,不影响应用使用内存。

真正要关注的是 available,只要 available 还够用,buff/cache 高就没问题。只有同时出现 available 持续下降 + 应用 OOM,才需要考虑释放缓存或调整 flush_methodO_DIRECT

场景五:应用反馈"写入慢",但查询正常

现象:

  • INSERT/UPDATE 慢,SELECT 正常
  • iostat 看到 w/s 很高,%util 接近 100%

排查步骤:

bash 复制代码
# 1. 确认 MySQL 日志刷盘配置
mysql -e "SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';"
mysql -e "SHOW VARIABLES LIKE 'sync_binlog';"

# 2. 追踪一下 fsync
timeout 20 strace -f -e trace=fsync,fdatasync -p $(pgrep -x mysqld | head -1) -c

对照实验结论:

实验里 strace 显示 20 秒内有 30,880 次 fsync + fdatasync,平均每秒 1544 次。这就是写入慢的直接原因:每笔事务提交要等 2 次 fsync 返回

SELECT 不受影响,因为查询不涉及事务提交,不需要等 fsync

判断结论:

如果业务能接受少量数据丢失,把双 1 改成 innodb_flush_log_at_trx_commit=2 + sync_binlog=0,写入速度会有数量级的提升(你实验里 754 TPS 可以翻几倍)。前提是业务方接受宕机时丢几秒数据。

总结:

| | | |
|----------------|---------------------------|---------------------------------------------|---------------|
| 线上问题 | 要用到的实验知识 | 验证命令 |
| 性能突然下降 | Page Cache 被清空的影响 | `cat /proc/meminfo | grep Cached` |
| 写入慢,查询正常 | 双1配置 + fsync频率 | strace -cfsync次数 |
| 磁盘利用率 100% | fsync需求 = TPS × 2 | iostat -dx 1%util |
| buff/cache太高 | Page Cache 机制 | 看 available,只要够用就没事 |
| O_DIRECT 配置困惑 | 数据文件绕过 Page Cache,日志文件不绕过 | SHOW VARIABLES LIKE 'innodb_flush_method' |

相关推荐
路由侠内网穿透.1 小时前
本地部署开源日志收集系统 Log Bull 并实现外部访问
运维·服务器·网络·数据库·开源
sevenll072 小时前
SqlKit - 覆盖 50+ 数据库的 AI 智能体 SQL 桌面客户端
数据库·人工智能·sql·智能体
数智化管理手记5 小时前
手工统计指标误差大、效率低?指标管理系统如何告别人工算数痛点?
大数据·运维·数据库·人工智能·云计算
ShiXZ21311 小时前
Redis 常用指令全集:redis-cli 实战速查手册
数据库·redis·缓存
晓子文集11 小时前
Tushare接口文档:期货日线行情(fut_daily)
大数据·数据库·金融数据·量化投资·tushare
WA内核拾荒者12 小时前
WhatsApp 账号异常检测的自动化告警系统设计
数据库·python·自动化
龙仔72515 小时前
人大金仓OS_Core数据库自动备份实施笔记(银河麒麟Linux)
linux·数据库·笔记·备份·人大金仓
sunxr.22716 小时前
Mysql-----最后一次作业
数据库·mysql
普通网友16 小时前
Python FastAPI 异步数据库管理
数据库·fastapi