overlay2 为什么对数据库不友好
这是一个非常关键、也非常容易被误解的问题。
内容:结论先行 -> 原理拆解 -> 实战层面的判断标准,和 UnionFS / overlay2 / 内核 / 数据库 串起来。
overlay2 不适合数据库的根本原因是: 数据库需要“稳定、可预测、顺序一致的本地写入”, 而 overlay2 提供的是“分层 + 写时复制 + 间接路径”的文件语义。
- 镜像分层
- 容器快速启动
- 文件共享
- 写少、读多
- 应用无状态
- 高频小写
- fsync / fdatasync 强一致
- 顺序写(WAL / redo / binlog)
- 稳定 inode
- 可预测的 IO 延迟
👉 目标完全相反
overlay2 写文件的真实过程:
写文件
↓
判断是否在 lowerdir
↓
复制整个文件到 upperdir
↓
再写
对数据库意味着:
- WAL 文件
- redo log
- 数据文件
👉 一次小写,可能触发整文件复制
📌 结果:
- IO 放大
- 延迟抖动
- 写性能不可预测
数据库认为:
fsync() = 数据已安全落盘
但 overlay2 实际路径是:
数据库
-> VFS
-> overlayfs
-> upperdir
-> 宿主文件系统
⚠️ 问题:
- fsync 在 overlay 层完成
- 不等价于物理磁盘 flush
- 特定内核版本下存在 fsync 语义漏洞
👉 数据库最怕“我以为写成功了,其实没有”
overlay2 的文件:
- 可能被 copy-up
- inode 会变化
- hard link / rename 行为不一致
数据库依赖:
- inode 稳定性
- rename 原子性
- 文件元数据一致性
📌 历史上:
- PostgreSQL
- MySQL InnoDB
都曾明确指出:
UnionFS 不完全符合数据库文件系统假设
数据库的 IO 模式:
- 8KB / 16KB page
- 高频随机写
- redo / wal 顺序追加
overlay2:
- 多层 lookup
- metadata 操作多
- dentry cache 压力大
👉 IO 延迟尾部极长(P99、P999)
overlay2 + 数据库:
- 宿主机 crash
- 容器 crash
- 强制 kill
⚠️ 风险点:
- overlay 层状态未完全 sync
- workdir 中间状态
- 数据文件与 WAL 不一致
👉 数据库最怕“恢复不了”
数据库通常要调:
- filesystem mount options
- barrier / journal
- discard / noatime
- direct IO
overlay2:
- mount 是 Docker 管
- 容器内不可控
- 数据库调优失效
| 场景 | 是否建议 |
|---|---|
| 本地开发 | ✅ |
| CI / 测试 | ✅ |
| Demo | ✅ |
| 生产数据库 | ❌ |
| 高并发 / 高可靠 | ❌ |
这和你前一个问题正好接上 👇
❌ 不是 overlay2 上直接写数据
而是:
| 层级 | 做法 |
|---|---|
| 容器 | 只跑数据库进程 |
| 数据目录 | bind mount / block device |
| 文件系统 | ext4 / xfs 直写 |
| 存储 | 本地 SSD / NVMe / 网络块存储 |
| cgroups | 精细隔离 |
| 内核 | 专门调优 |
📌 关键点:
/var/lib/mysql
-> 不在 overlay2
-> 在真实文件系统
docker run \
-v /data/mysql:/var/lib/mysql \
mysql
数据绕过 overlay2,直写宿主机 FS
- LVM
- iSCSI
- 云盘
--mount type=bind,source=/dev/mapper/mysql,target=/var/lib/mysql
docker run mysql
## 数据写在 overlay2
overlay2 适合“应用层文件”,不适合“数据库存储层文件”。 数据库必须绕过 UnionFS,直达真实文件系统。