为什么别人在Linux上创建100G文件只要0.01秒,你却要好几分钟?
为什么别人在Linux上创建100G文件只要0.01秒你却要好几分钟上次给新服务器做磁盘压测需要先创建几个100G的测试文件把盘填满。我习惯性敲了dd if/dev/zero of/data/test.bin bs1G count100然后盯着光标看它一格一格地闪。**过了两分钟还没跑完。**我打开另一个终端 ssh 上去同事给我发了一条命令fallocate -l 100G /data/test2.bin回车瞬间结束。ls -lh一看100G的文件已经在那了。但兴奋劲儿过去之后我心里冒出一个疑问我是来做磁盘压测的压测不就是考验磁盘真实读写能力吗他这命令连数据都没写压了个什么这个问题恰好指向了创建大文件这件事的底层真相——一直有两种完全不同的做法一种是真往里搬东西另一种是只到登记簿上划块地。dd最老实的方法也是最慢的dd**是 Linux 里最经典的搬运工。**它的工作方式很直白dd if/dev/zero of/data/test.bin bs1G count100这行命令的意思是从/dev/zero这个空数据水龙头里每次接 1G 的水往/data/test.bin这个池子里倒一共倒 100 次。你想象一个仓库。dd 的做法是打开库房大门真的往里搬箱子——一个箱子 1G 大搬 100 个结结实实码进去。搬完之后库房里确实堆了 100G 的东西。所以 dd 创建 100G 文件花了几分钟。这时间全是 IO 时间——磁盘在真实地写入 零字节。/dev/zero是个特殊设备文件读它的时候内核直接给你返回一串零不需要从任何物理设备读取。这也是为什么 dd 不会卡在读这一步——瓶颈全在写。yes箱子里的东西不一样但还是要搬dd 搬进仓库的都是空箱子。如果你希望箱子里装点具体的东西——比如模拟日志做 grep 测试——yes 登场yesERROR: connection timeout|head-c 100G /data/test.log还是仓库场景。dd 是从/dev/zero流水线上接空箱子往仓库里搬yes 是从一条标签打印机上接箱子——每个箱子都贴着同一句 “ERROR: connection timeout”。head -c 10G在第 100G 个箱子过传送带的时候按停。结果一样仓库里堆了 100G 的箱子。但本质没变——yes 也在实打实地搬箱子。不管箱子里装的是空气还是标签搬运的活一样不少。所以 10G 耗时和 dd 差不多也要 20 多秒。如果你是一个程序员看到这里心里可能在想“那是不是换个更快的数据源就行了比如不用/dev/zero用/dev/urandom”不是数据源的问题。dd 慢、yes 也慢——它们慢在同一个地方往磁盘上写东西这个动作本身。不管写什么、从哪读、用什么工具只要你在搬箱子时间就少不了。两轮实验指向同一个结论真写数据这条路的终点就是 20 多秒换个姿势也没用。要突破这个天花板只能换一条路——不搬箱子。fallocate不搬箱子只划地盘这是Linux 给你的第三条路。fallocate根本不参与搬运fallocate -l 100G /data/test.bin还是仓库的比喻。dd 是搬箱子进去而 fallocate 是拿一支笔在仓库的登记簿上写“10号到210号货架归 /data/test.bin 用了。”箱子呢一个都没搬。但登记簿已经写好了任何人来查这 100G 空间就是已经被占用的。**所以 fallocate 创建 100G 文件只要 0.01 秒。**它不是偷懒——它是在文件系统层面做了一件完全不同的事预分配空间。**文件系统管理磁盘时维护着一张空间分配表extent map。每个文件占用哪些磁盘块都登记在这张表里。**dd 的做法是先写数据 → 写的时候顺便登记占用了哪些块。而 fallocate 的做法是直接在表里登记占用 → 数据区域压根不碰。这就是为什么同样的 100G 文件一个要以分钟计算一个只要 0.01 秒。那文件里到底有什么很多人听到这里会问fallocate 创建的文件读出来是什么答案是零。文件系统有个约定如果空间被分配了但从来没写过数据读的时候内核会自动返回零。这不是 fallocate 提前写了零进去而是文件系统在读这一步做了补位——“这块地登记了但没货那就按零处理。”所以从使用者的角度看dd 和 fallocate 创建的文件在读取时表现一样——都是满屏的零字节。区别只在于磁盘上的物理状态dd 的文件是真的写满了零fallocate 的文件只是标记为已占用。认知跃迁反过来理解稀疏文件理解了 fallocate 只登记不搬货你就会顿悟Linux 文件系统的另一个反直觉特性稀疏文件——它反过来搬了货但不占那么多登记空间。ddif/dev/zero of/data/sparse.bin bs1 count1 seek100G这条命令在仓库登记簿上写这文件占了 100G 的货架但实际只在第 100G 的位置放了一个小箱子。用ls -lh看文件 10G用du -h看实际物理占用可能只有几 KB。这就是 fallocate 的镜像——fallocate 是登记了但没货稀疏文件是登记了 100G 但只有一个箱子真有东西。一个 extents map两种玩法**向前是预分配fallocate向后是延迟分配稀疏文件。**理解了这个你就不是在记三个命令了——你是在理解文件系统怎么管空间。回到你面前你到底要什么记住整篇文章的核心就够了创建文件只有两种本质——真写数据和只分配空间。选工具就是在这两种本质之间做选择。如果你要的只是占个位置——填磁盘、做空间测试、临时占个坑——你就站在只分配空间这边。fallocate -l 10G /data/test.bin回车搞定。这是整篇文章想让你记住的最重要的一件事。如果你要的是文件里有内容——模拟日志、造测试数据、测 grep 性能——那你就必须走真写数据这条路。dd 往里写零yes 往里写字符串跑 20 多秒是物理定律不是你没选对工具。如果你要的是测 IO 带宽——想知道磁盘真实的写入吞吐——也一样只有真写能告诉你答案。这时候 dd 不是慢它是在替你干正事。每个字节都过了磁盘控制器每毫秒都是你要的数据。一个容易踩的坑拿 dd 做磁盘填满测试然后下结论这台服务器 IO 不行——你测的不是空间分配速度是写入带宽。把占坑的活交给了搬箱子的人当然觉得慢。