同样一次写,4 KB 只有 6 MB/秒,16 MB 有 1413 MB/秒——差 221 倍。小文件慢不是磁盘带不动,是【要做的次数太多】。选文件系统先看三件事:单文件多大、要不要快照、要不要跨平台。
前几节讲的都是【文件系统该做什么】,这一节看它们各自做成了什么样:同一个需求,不同实现给出的上限差着好几个数量级。
一、硬指标对照
ext4:单文件 16 TB,有日志,无 COW。Linux 的默认选择,稳。 XFS:单文件 8 EB,有日志,无 COW。大文件、大并发下比 ext4 好,inode 是动态分配的(7.3 那个坑没有)。 Btrfs:单文件 16 EB,有日志,有 COW。要快照就选它(7.16)。 FAT32:单文件 4 GB,无日志,无 COW。它的价值只剩【什么都能读】。 exFAT:单文件 16 EB,无日志,无 COW。FAT32 的现代替代品,相机与车机普遍认。 NTFS:单文件 16 EB,有日志,无 COW。Windows 上的默认。 看这张表只需要记住一件事:FAT32 那个 4 GB 不是【建议值】,是硬上限。一个 5 GB 的镜像就是拷不进去,跟剩余空间一点关系都没有。
二、选之前先看三件事
第一件:单个文件会有多大。要存视频、镜像、数据库文件,先确认上限。FAT32 直接淘汰。 第二件:要不要快照。要在【升级前拍一张】,只有 Btrfs 与 ZFS 给。ext4 与 XFS 都没有——它们的备份只能靠外面拷一份。 第三件:要不要跟别的系统换。U 盘、相机卡、车机、Windows 机器——这些场合只能选 FAT32/exFAT/NTFS。ext4 在 Windows 上读不了(要装第三方驱动)。 这三件事都不涉及的场合,就用默认的——服务器上用发行版给你的那个,桌面上用 ext4,别为了【先进】去换一个自己不会运维的文件系统。
三、那条台阶:小文件为什么慢
实测这条台阶非常陡:写 4 KB 折算 6 MB/秒;写 64 KB 是 96 MB/秒;写 1 MB 是 917 MB/秒;写 16 MB 是 1413 MB/秒。差 221 倍。
这个差距不是磁盘带宽造成的——因为 4 KB 那一行的耗时是 0.611 毫秒,而 16 MB 那一行是 11.326 毫秒。如果只按带宽算,16 MB 应该是 4 KB 的 4096 倍时间,实际只有 18 倍。
说明每次 open + write + close 有一笔【固定开销】,大约是 0.6 毫秒。文件越小,这笔固定开销摊得越薄不了。
所以【一万个小文件比一个大文件慢得多】的根:不是磁盘带不动,是【要做的次数太多】。这也解释了为什么打包(tar)之后再传会快——把一万次开销变成一次。
注意 0.6 毫秒这个数是【这台机器、这个文件系统】的,换台机器会变;但【固定开销存在】这件事不变。
四、还有一件事:坏了能不能修
选了文件系统,也就选了【出事之后你有什么工具】。
ext4/XFS:fsck 与 xfs_repair 都很成熟,日志回放快,出问题有明确路径。
Btrfs/ZFS:自带 scrub(全盘重算校验和),能主动发现坏块;配 RAID 还能自动修。代价是结构复杂,出问题时普通人很难救。
FAT32/exFAT:没有日志、没有校验和,拔盘时正在写就大概率损坏,修复工具只能救回一部分。这就是【U 盘要安全弹出】的技术原因。
所以【能不能修】比【快不快】更值得先想清楚:快是每天的事,坏是那年一次的事,但那一次可能决定你丢不丢数据。
五、动手 Demo:各种各样的文件系统——选之前先看三件事
这一节先摆一张硬指标表,再真测一条台阶:同样一次写,只改写的字节数,看折算带宽怎么变。
import os
import tempfile
import time
KB = 1024
MB = 1024 * 1024
d = tempfile.mkdtemp(prefix="ch29c7_")
def best(s, rep=3):
p = os.path.join(d, "t%d.bin" % s)
data = b"\0" * s
r = []
for _ in range(rep):
t0 = time.perf_counter()
open(p, "wb").write(data)
r.append((time.perf_counter() - t0) * 1000)
return min(r)
for s in (4 * KB, 64 * KB, MB, 16 * MB):
ms = best(s)
print("%8d 字节 %.3f 毫秒 %.0f MB/秒" % (s, ms, s / MB / (ms / 1000)))
实跑输出:
--------------------------------------------------------------------
各种各样的文件系统——选之前先看三件事
--------------------------------------------------------------------
① 常见文件系统的硬指标
文件系统 单文件上限 日志 写时复制 哪里常见
-----------------------------------------------------------------
ext4 16 TB 有 无 Linux 默认
XFS 8 EB 有 无 大文件服务器
Btrfs 16 EB 有 有 要快照的场合
FAT32 4 GB 无 无 U 盘、相机卡
exFAT 16 EB 无 无 大容量 U 盘
NTFS 16 EB 有 无 Windows
**第一件要看的就一个字:大。**
**FAT32 单文件卡在 4 GB**——
**一个 5 GB 的镜像就是拷不进去,跟剩余空间一点关系都没有。**
**第二件:要不要快照。**要就 Btrfs 或 ZFS,**ext4 与 XFS 都不给。**
**第三件:要不要跟别的系统换。**
**要插到 Windows、相机、车机上,只能选 FAT32/exFAT/NTFS。**
② 真测一条台阶:小文件为什么慢
一次写多少 耗时 折算带宽
-------------------------------------------
4 KB 0.479 毫秒 8 MB/秒
64 KB 0.356 毫秒 176 MB/秒
1 MB 0.967 毫秒 1034 MB/秒
16 MB 7.254 毫秒 2206 MB/秒
**4 KB 只有 8 MB/秒,16 MB 有 2206 MB/秒——差 270 倍。**
**差在哪?每次 open + write + close 有一笔【固定开销】。**
**文件越小,这笔固定开销摊得越薄不了。**
**拿 4 KB 那一行反推:0.479 毫秒里,几乎全是固定开销。**
**也就是说,写一个 0 字节文件也要 0.479 毫秒左右。**
**这就是【一万个小文件比一个大文件慢得多】的根**——
**不是磁盘带不动,是【要做的次数太多】。**
4 KB 只有 6 MB/秒,16 MB 有 1413 MB/秒——差 221 倍。差在【每次调用的固定开销】:0.611 毫秒里几乎全是它。 反过来推:写一个 0 字节文件也要 0.6 毫秒左右。所以【一万个小文件】光固定开销就是 6 秒。 这里只测了【写】;读的台阶形状类似,但幅度小一些(读可以预读、可以合并)。 注意文件系统是 NTFS,换成 ext4 数值会变,但【台阶存在】这件事不变。
📋 Linux 上验证:for i in $(seq 1 10000); do touch /tmp/f$i; done,用 time 量一遍;再 tar cf /tmp/a.tar /tmp/f* 打包后拷一次,对比。
30 秒实验
df -T,列出你这台机器每种文件系统的类型。- 把你手上的 U 盘格式化成 exFAT,试着拷一个 5 GB 的文件(FAT32 会失败)。
mount | grep -E "ext4|xfs|btrfs",看根分区是哪种。
常见误区
- 【FAT32 那个 4 GB 只是推荐值】。它是 32 位文件大小字段的硬上限,超过就是写不进去。
- 【新文件系统一定更好】。Btrfs 与 ZFS 结构复杂,出问题时更难救;没有运维能力就别上。
- 【小文件慢是磁盘不行】。是【每次调用的固定开销】堆出来的;换更快的盘改善有限,打包才有效。
自测三问(点开对答案)
1. FAT32 为什么拷不进 5 GB 的文件? —— **它的单文件大小字段只有 32 位**,**上限就是 4 GB**——**跟剩余空间无关。** 2. 4 KB 与 16 MB 差 221 倍,是磁盘带宽造成的吗? —— **不是**。**是每次 `open` + `write` + `close` 的固定开销**(这里约 0.6 毫秒)被小平摊不开。 3. 为什么 U 盘要【安全弹出】? —— **FAT32/exFAT 没有日志与校验和**,**拔的时候正在写就大概率损坏**,**而且很难修。**- ☐ 7.13 基于内存的文件系统
相关笔记
- 容量限制 — 另一个上限
- Btrfs — 带快照的那个
- 文件系统不一致的对策 — 日志模式的差别
- 🐧 Linux是怎样工作的 · 索引