我观察到使用 `dd if=filein of=fileout` 会导致文件系统碎片,我需要更改什么?

Mar*_*ler 6 filesystems dd defragmentation

有一个很好的问题,遗憾的是在我写一个相当广泛的答案时被删除了:(

\n

不想让这种努力白费,让我从问题文本和评论中解释一下这个问题:

\n
\n

我观察到使用dd覆盖文件确实会增加碎片。我正在寻找一种dd不会导致碎片化的替代方案。

\n

作为碎片如何发生的示例:想象一个占据整个文件系统的文件。开始覆盖它,您将立即看到该分区如何变得完全“空闲”,同时您将能够向其中写入另一个文件。块是动态分配的,并且当文件被覆盖时,零保证旧块将被重用。

\n

我在多个文件系统(ext2、3 和 4、XFS、以及 FAT32 和 NTFS)和多个操作系统(win95 到现代 Fedora)\xc2\xb2 上观察到这种行为。

\n

我确信这与文件系统和操作系统无关。

\n

我的主文件系统是 Bog 标准 ext4。FedoraROOT:103874/1310720 个文件(0.2% 不连续),1754833/5242880 个块。最小的整体碎片。

\n
\n
\n

请注意,自己无法观察到这一点,我相信这些碎片声明的原始提问者!

\n

Mar*_*ler 4

太长了;博士!我应该使用什么工具来代替ddcp:如果您的 GNU coreutils 足够新,那就是。

\n

实际的文件系统来救援

\n

这根本不独立于文件系统和操作系统!块到文件的分配是特定文件系统的特定情况,它们之间存在差异。所以,它不能严格独立!

\n

Ext4 的延迟分配来拯救

\n

Ext4 支持allocate-on-flush:在数据刷新到磁盘时将块分配给文件,而不是更早。这意味着,如果您的系统(现代 Fedora 肯定会这样做)使用文件系统缓冲区,则顺序扩展的文件的分配大小会非常大,因此碎片会非常低。您可以激活它,之后无需执行任何操作,只需使用cpdd(我更喜欢cp,因为这不仅解决了您的第一个问题,还解决了您的第二个问题!)。

\n

在 ext4 中,这称为延迟分配;只需添加delalloc安装选项即可!(看man ext4

\n

使用cpwill (在现代 Fedora 上)使用copy_file_range,然后在将内容刷新到磁盘时导致连续分配。

\n

XFS 来救援

\n

XFS默认做延迟分配;参见 ext4。

\n

相同的文件系统:reflink

\n

当您使用cpFedora >=34 或 GNU coreutils >=9.0时cp,它支持reflinks,即根本不支持复制数据,而是简单地将块标记为由两个文件使用,并且如果其中一个文件发生更改,则仅制作一份副本。这是一个非常好的功能,但当然只有当源文件和目标文件位于同一文件系统上时才有效。

\n

效果是目标文件与源文件完全相同(未碎片化),因为它们实际上是相同的块。

\n

不同的文件系统:XFS 分配组

\n

XFS 不会将可用空间和已用空间作为整个文件系统的“一件事”进行管理,它具有多个分配组。引用man xfs

\n
\n

数据部分包含所有文件系统元数据(索引节点、目录、间接块)以及普通(非实时)文件的用户文件数据和日志区域(如果日志位于数据部分内部)。数据部分被分为多个分配组。分配组的数量和大小由 mkfs.xfs(8) 选择,因此通常存在少量相同大小的组。分配组的数量控制着文件和块分配中可用的并行度。如果有足够的内存和大量的分配活动,则应增加默认值。分配组的数量不应设置得太高,因为这可能会导致文件系统使用大量 CPU 时间,尤其是当文件系统几乎已满时。运行 xfs_growfs(8) 时,\n会添加更多分配组(原始大小)。

\n
\n

所以,要解决“并发分配导致碎片”的问题,你只需要足够的分配组即可!我希望一个大小合理的文件系统有几个,但只需从默认值增加计数(我对 4 设备条带 LVM 卷使用 5 个,这样看起来性能良好)就可以了。但是,您需要重新格式化或添加更多存储,才能增加分配组的数量。

\n

救援工具

\n

dd不是用另一个文件覆盖文件的首选工具:cp是;它会在当前版本(9.0)和 Fedora 附带的版本(带有 Fedora 补丁的 8.32)中使用copy_file_range,它告诉底层文件系统最终将复制多少数据 \xe2\x80\x93 ,以便分配简单在块上工作。

\n

  • 如果 cp 不使用 copy_file_range() ,它可能只是使用 O_WRONLY|O_TRUNC 来打开目标文件,这可能会导致先前分配的块被释放并进行新的分配。(这就是我尝试时在 Ubuntu 22.04 上的 coreutils 8.32 中执行的 cp 操作,我将其视为原始问题。)像 `cat srcfile 1<> dstfile && truncate -r srcfile dstfile` 这样的东西可能会实际覆盖文件并随后将其截断至长度。 (2认同)