写入方式、COW 与写放大
明白了,你希望这个文档 在博客园或者 Markdown 环境下显示效果更美观,排版整齐、表格和代码块清晰、层级逻辑一目了然。我帮你彻底优化一下格式,兼顾可读性和视觉效果:
Linux 写入方式、COW 与写放大(Write Amplification)
1️⃣ 写时复制(Copy-On-Write, COW)
定义
多个进程或对象共享同一块内存/文件页,当某个进程写入时,内核才真正复制一份新的副本,保证原有共享者不受影响。
核心思想
读共享,写复制
典型应用场景
-
fork()
子进程继承父进程地址空间(写时才复制页) -
mmap(MAP_PRIVATE)
映射文件,写入触发复制 -
文件系统(ZFS/Btrfs/APFS)写入数据块时生成新块,不覆盖旧块
2️⃣ 写入方式对比
写方式 | 是否涉及 COW | 说明 |
---|---|---|
正常写 (fwrite → write) | ❌ | 用户缓冲 → 内核缓冲 → 文件,独立通道 |
直写 (write + O_SYNC / O_DIRECT) | ❌ | 数据直接落盘,无共享页复制 |
mmap (MAP_SHARED) | ❌ | 修改直接影响文件,共享进程可见 |
mmap (MAP_PRIVATE) | ✅ | 写时触发 COW,进程得到私有副本 |
结论:COW 只在
mmap(MAP_PRIVATE)
或 fork 场景出现,正常写和直写不触发 COW。
3️⃣ 内核层控制点
写方式 | 内核参数 / 控制点 | 说明 |
---|---|---|
正常写 | vm.dirty_ratio / vm.dirty_background_ratio |
控制 page cache 脏页比例,决定何时刷盘 |
vm.dirty_expire_centisecs / vm.dirty_writeback_centisecs |
脏页过期时间 / 后台写回间隔 | |
mount -o sync / O_DSYNC / fdatasync() |
强制同步落盘 | |
直写 | O_SYNC / O_DSYNC / O_DIRECT |
阻塞写或绕过 page cache |
文件系统挂载选项 sync |
强制同步写入 | |
块设备参数 queue/nr_requests , scheduler |
I/O 调度器与队列大小影响延迟 | |
mmap(MAP_SHARED) | vm.dirty_* 系列参数 |
脏页写回策略,和正常写一致 |
msync() / fadvise(DONTNEED) |
用户显式控制写回或丢弃缓存 | |
mmap(MAP_PRIVATE, COW) | 写时复制机制 | 写页触发缺页异常 → 内核复制页 |
overcommit_memory / overcommit_ratio |
fork + COW 的内存分配策略 | |
transparent_hugepage |
大页 COW 行为,fork + THP 可能高成本 | |
KSM (Kernel Samepage Merging) |
跨进程页合并,间接影响 COW |
4️⃣ 数据库类比
数据库组件 | 写方式类比 | 是否触发 COW |
---|---|---|
MongoDB Diagnostic log | 正常写 | ❌ |
WiredTiger journal | 直写 (O_SYNC) | ❌ |
MMAPv1 引擎 (已废弃) | mmap | ✅ MAP_PRIVATE 时事务隔离使用 COW-like 行为 |
5️⃣ 写放大(Write Amplification)判断方法
5.1 应用层 → 内核层
-
症状:应用写少,但 Dirty 增长大于写入量
-
工具:
strace -e trace=write,mmap -p <pid>
5.2 内核层 → 文件系统
-
症状:块设备写量大于应用写量
-
工具:
pidstat -d -p <pid> 1
iostat -dx 1
cat /proc/diskstats
5.3 磁盘层(SSD / RAID)
-
症状:NAND 写量 > Host 写量
-
工具:
iostat -d -k /dev/nvme0n1
smartctl -A /dev/nvme0n1 | egrep "Data_Units_Written|Host_Writes_32MiB"
写放大因子 (WAF):
WAF = 实际磁盘写入字节 / 应用写入字节
-
理想接近 1
-
文件系统通常 1.1~2
-
数据库 + SSD 可能 2~5
6️⃣ 内核脏页参数调优(示例)
参数 | 建议值 | 说明 |
---|---|---|
dirty_background_bytes |
64~256 MB | 后台写回启动阈值 |
dirty_bytes |
512 MB~2 GB | 应用阻塞写回阈值 |
dirty_ratio |
5~10% | 内存百分比模式 |
/proc/meminfo:Dirty |
< dirty_bytes 50% | 写回调度正常 |
/proc/meminfo:Writeback |
不长期高 | I/O 系统跟不上 |
MongoDB Diagnostic log 场景:
dirty_background_bytes = 64~128MB
dirty_bytes = 512MB~1GB
保证日志落盘及时、避免写放大或阻塞。
7️⃣ 可视化 & 脚本思路
可视化:
-
绘制 mmap(MAP_SHARED vs MAP_PRIVATE) 写入示意图
-
两个进程共享文件页
-
写入 MAP_PRIVATE 时触发缺页复制,MAP_SHARED 直接修改共享页
脚本思路:
-
自动采集
/proc/meminfo
+dirty_*
参数 -
统计应用写入 (
pidstat
) -
统计块设备写入 (
iostat
) -
查询 SSD 内部写入 (
smartctl
) -
计算三层 WAF,输出“合理 / 偏高 / 偏低”
可以直接评估写放大是否存在,并判断系统参数是否合理。
如果你希望,我可以帮你 画一个直观的 mmap MAP_PRIVATE vs MAP_SHARED 的示意图,同时写一个 一键检测写放大的脚本,可以直接在生产环境跑。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/921983.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!