MySQL写入变慢需优先调I/O调度器(NVMe用none、SATA SSD用deadline)、控制重做日志总容量1G~4G、慎用O_DIRECT以防OOM、挂载云盘必加noatime,nobarrier,并逐项验证避免隐性冲突。

MySQL写入变慢,iotop显示磁盘等待高,先看I/O调度器
Linux默认的cfq调度器在SSD或NVMe上反而拖累MySQL吞吐,尤其高并发INSERT/UPDATE场景下,I/O延迟抖动明显。换成none(NVMe)或deadline(SATA SSD)能直接降低平均写延迟20%~40%。
- 查当前调度器:
cat /sys/block/nvme0n1/queue/scheduler(设备名按lsblk确认) - 临时切换(重启失效):
echo none > /sys/block/nvme0n1/queue/scheduler - 永久生效需改
/etc/default/grub,在GRUB_CMDLINE_LINUX里加elevator=none,再update-grub && reboot - 别对机械盘用
none——它没队列管理能力,会加剧寻道开销
innodb_log_file_size调太大反而卡住启动
InnoDB重做日志不是越大越好。设成单个4G以上时,MySQL启动阶段要做崩溃恢复扫描,若上次异常退出,可能卡住几十秒甚至几分钟,线上服务等不及就超时失败。
- 常规建议:总日志容量(
innodb_log_files_in_group × innodb_log_file_size)控制在1G~4G之间 - 调大前必须停库,删旧
ib_logfile*,再启;不能在线改 - 如果写入峰值持续高(如批量导入),优先调
innodb_log_buffer_size和innodb_flush_log_at_trx_commit=2,比硬扩日志文件更安全 - 注意
innodb_log_file_size变更后,SHOW VARIABLES LIKE 'innodb_log%'不会立刻反映新值,得看SHOW ENGINE INNODB STATUS里的Log部分
启用innodb_flush_method=O_DIRECT后内存占用飙升
O_DIRECT绕过OS缓存,本意是避免双重缓存(InnoDB buffer pool + page cache)浪费内存,但实际中常导致mysqld进程RSS暴涨,甚至OOM kill——因为InnoDB自己分配的大块内存没被及时归还给系统,尤其在大量临时表或排序操作后。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 只在专用DB服务器、内存充足(≥64G)、且确认OS缓存没被其他进程争抢时才开
O_DIRECT - 若用LVM或某些云盘(如AWS gp3),
O_DIRECT可能触发额外IO路径,反而降低吞吐,先压测对比fdatasync - 配合调低
innodb_buffer_pool_instances(比如从16降到8),减少内存碎片,缓解RSS虚高 - 监控关键指标:
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_%'+ps aux --sort=-%mem | head -5
云环境挂载高性能盘,/etc/fstab漏了noatime,nobarrier
云盘(如阿里云ESSD、腾讯云CBS Turbo)本身已做元数据持久化,Linux默认挂载的barrier=1和每次读都更新atime,纯属冗余开销,单次INSERT可能多出0.1~0.3ms延迟。
- 挂载选项必须含
noatime(禁用访问时间更新)和nobarrier(禁用写屏障) - 示例fstab行:
/dev/nvme1n1 /var/lib/mysql xfs defaults,noatime,nobarrier 0 0 -
nobarrier仅适用于有断电保护的存储(所有主流云盘都满足),本地机械盘禁用会丢数据 - 改完要
umount /var/lib/mysql && mount /var/lib/mysql,别只mount -o remount——部分内核版本不生效
真正卡顿往往不在参数本身,而在多个优化叠加后的隐性冲突:比如开了O_DIRECT又没关barrier,或者log_file_size调大后忘了调innodb_log_buffer_size,结果buffer pool反复刷脏页。每个改动都得单独验证,别一口气全上。










