
DMC对应的英文通常是:
先定核心结论:DMC(Dirty脏缓存 / Metadata元数据缓存 / Cache Coherence缓存一致性) 不是 Ceph 分布式专属问题;
只要是 Linux + Ext4/XFS 本地文件系统,
依赖 Linux 标准 IO 缓存架构,天生自带 DMC 三大问题。
根源不在分布式, 而在于 Linux 为了性能,强行引入的页缓存(Page Cache)、延迟写、元数据缓存机制。
同样基于缓存架构, 数据库不仅会遇到 DMC 问题,而且比普通文件系统更严重。
因为数据库在操作系统 PageCache 之上, 又构建了自己的专属缓存层, 形成了双层缓存架构,让问题叠加放大。
MySQL(InnoDB)和 TiKV 作为两种典型的单机 / 分布式存储引擎,都面临 DMC 三大挑战,但由于底层架构(B + 树 vs LSM-Tree、单机 vs 分布式)不同,问题表现和解决方式有本质区别
基于循序渐进的原则,本文先将目光聚焦于文件系统层的 DMC 问题。
实在是不能在截至日期完成同时一次解决三个问题,不 同时支持多个项目,这样反人性安排谁设计的?
硬件天然速度鸿沟:
Linux 为了不让慢速磁盘拖垮应用性能,设计一套强制 IO 优化架构:
所有文件读写不直接读写磁盘,全部先过 PageCache 页缓存
这套「内存缓存 + 延迟落盘」的 IO 优化机制,直接催生了 D、M、C 全部问题。
应用写文件(非O_DIRECT) → 数据仅写入 Linux PageCache(脏页)→ 内核未同步到磁盘 → 系统异常崩溃 → 内存数据丢失[返回用户写入成功] → 磁盘数据为旧数据【实际没有写入成功】 → 数据不一致
Vdbench 开启 data_validation=yes 后, 会给每个数据块写入全局唯一签名,读取时自动校验, 精准识别 Dirty Cache 导致的不一致。
# 基础配置
sd=sd1,lun=/test/disk_1.img,size=10G,openflags=async
# openflags=async:走PageCache,禁用DirectIO
wd=wd1,sd=sd1,rdpct=0,rhpct=0,whpct=100
# 100% 随机写
rd=rd1,wd=wd1,iorate=max,elapsed=60,interval=1 # 运行60秒
# 【核心】开启数据一致性校验
data_validation=yes
validate=yes
核心错误类型:数据校验失败(Data Validation miscompare),包含 4 类不匹配:
dirty_ratio,应用被阻塞等待刷盘👉 结论:只要 Linux 用延迟写 + PageCache,Ext4 必然有 D 脏缓存问题。
inode、目录项 dentry、文件大小、权限、时间戳、块位图、超级块。
业务 70% 操作都是元数据操作:ls、stat、open、mkdir、rm、遍历目录
如果每次都从 Ext4 磁盘读 inode/目录:
所以 Linux 把 Ext4 元数据全部缓存到内存:Dentry Cache + Inode Cache
某日志服务器每小时切割 10 万个 1KB 日志文件 → 切割瞬间,元数据刷盘导致 IO 利用率 100% → 日志写入延迟从 1ms 飙升到 500ms → 应用日志堆积、报警触发。
rm test.txt 后,ls 看不到文件(内存缓存已更新),但此时断电 → 重启后文件又「复活」(磁盘元数据未刷盘);cp test.txt new.txt 后,ls 能看到 new.txt,但断电后 new.txt 变成空文件(文件内容刷盘了,但元数据没刷) 👉 结论:只要有文件系统、只要要性能,就必须缓存元数据,M 问题躲不开。同一台 Linux 上,多进程/多线程 同时读写同一个 Ext4 文件。
每个进程都依赖内核同一个 PageCache:

PageCache 和普通malloc 分配内存有什么区别?
test.txt 加载到 PageCache,进程 B 再读 test.txt 直接复用,节省内存 + 提升速度;malloc(1GB),进程 B 也 malloc(1GB),系统会分配 2GB 内存(互不共享)内核管 PageCache,进程管 malloc
free PageCache,只能通过 sync 触发刷盘,或通过 echo 3 > /proc/sys/vm/drop_caches 让内核回收;内核必须做:
问题 2:mmap 共享文件场景
具体表现:
mmap原理:
只有满足以下被动条件才会刷盘:
vm.dirty_background_ratio(默认 10%):后台异步刷盘,不阻塞进程;vm.dirty_ratio(默认 20%):强制刷盘,阻塞写进程;vm.dirty_expire_centisecs,默认 3000=30 秒):超时未刷的脏页会被刷盘;dirty_background_ratio 是 Linux 内核中控制脏页异步刷盘触发阈值的核心参数,直接决定了 mmap / 普通写产生的脏页何时被 flusher 线程异步刷盘
方法1:sysctl 查看(推荐) sysctl vm.dirty_background_ratio 方法2:直接读 proc 文件 cat /proc/sys/vm/dirty_background_ratio 10%
👉 结论:只要多进程共享文件,单机 Ext4 就天然存在缓存一致性 C 问题。
不是没有 DMC,是单机代价小、不放大。
一句话终极总结(从普通文件系统角度)