当设备有足够的空间时,如何在 mv 期间修复间歇性的“设备上没有剩余空间”错误?

Chr*_*ell 21 linux command-line ubuntu ext4

  • 桌面上的 Ubuntu 14.04
  • 源驱动器:/dev/sda1:5TB ext4 单
    驱动器卷
  • 目标卷:/dev/mapper/archive-lvarchive:raid6 (mdadm) 18TB 卷,带 lvm
    分区和 ext4

大约有 1500 万个文件要移动,有些可能是重复的(我不想覆盖重复的)。

使用的命令(来自源目录)是:

ls -U |xargs -i -t mv -n {} /mnt/archive/targetDir/{}
Run Code Online (Sandbox Code Playgroud)

这已经按预期持续了几天,但我收到了增加频率的错误。当它开始时,目标驱动器大约为 70%,现在大约为 90%。过去大约有 1/200 的动作会出现状态和错误,现在大约是 1/5。没有一个文件超过 100Mb,大多数都在 100k 左右

一些信息:

$ df -h
Filesystem                     Size  Used Avail Use% Mounted on
/dev/sdb3                      155G  5.5G  142G   4% /
none                           4.0K     0  4.0K   0% /sys/fs/cgroup
udev                           3.9G  4.0K  3.9G   1% /dev
tmpfs                          797M  2.9M  794M   1% /run
none                           5.0M  4.0K  5.0M   1% /run/lock
none                           3.9G     0  3.9G   0% /run/shm
none                           100M     0  100M   0% /run/user
/dev/sdb1                       19G   78M   18G   1% /boot
/dev/mapper/archive-lvarchive   18T   15T  1.8T  90% /mnt/archive
/dev/sda1                      4.6T  1.1T  3.3T  25% /mnt/tmp

$ df -i
Filesystem                       Inodes    IUsed     IFree IUse% Mounted on
/dev/sdb3                      10297344   222248  10075096    3% /
none                            1019711        4   1019707    1% /sys/fs/cgroup
udev                            1016768      500   1016268    1% /dev
tmpfs                           1019711     1022   1018689    1% /run
none                            1019711        5   1019706    1% /run/lock
none                            1019711        1   1019710    1% /run/shm
none                            1019711        2   1019709    1% /run/user
/dev/sdb1                       4940000      582   4939418    1% /boot
/dev/mapper/archive-lvarchive 289966080 44899541 245066539   16% /mnt/archive
/dev/sda1                     152621056  5391544 147229512    4% /mnt/tmp
Run Code Online (Sandbox Code Playgroud)

这是我的输出:

mv -n 747265521.pdf /mnt/archive/targetDir/747265521.pdf 
mv -n 61078318.pdf /mnt/archive/targetDir/61078318.pdf 
mv -n 709099107.pdf /mnt/archive/targetDir/709099107.pdf 
mv -n 75286077.pdf /mnt/archive/targetDir/75286077.pdf 
mv: cannot create regular file ‘/mnt/archive/targetDir/75286077.pdf’: No space left on device
mv -n 796522548.pdf /mnt/archive/targetDir/796522548.pdf 
mv: cannot create regular file ‘/mnt/archive/targetDir/796522548.pdf’: No space left on device
mv -n 685163563.pdf /mnt/archive/targetDir/685163563.pdf 
mv -n 701433025.pdf /mnt/archive/targetDir/701433025.pd
Run Code Online (Sandbox Code Playgroud)

我发现很多关于这个错误的帖子,但预测不合适。诸如“您的驱动器实际上已满”或“您的 inode 已用完”甚至“您的 /boot 卷已满”之类的问题。但是,大多数情况下,他们处理由于处理文件的方式而导致问题的 3rd 方软件,并且它们都是恒定的,这意味着每次移动都会失败。

谢谢。

编辑:这是一个示例失败和成功的文件:

失败(仍在源驱动器上)

ls -lhs 702637545.pdf
16K -rw-rw-r-- 1 myUser myUser 16K Jul 24 20:52 702637545.pdf
Run Code Online (Sandbox Code Playgroud)

成功(在目标卷上)

ls -lhs /mnt/archive/targetDir/704886680.pdf
104K -rw-rw-r-- 1 myUser myUser 103K Jul 25 01:22 /mnt/archive/targetDir/704886680.pdf
Run Code Online (Sandbox Code Playgroud)

此外,虽然并非所有文件都失败,但失败的文件总是会失败。如果我一遍又一遍地重试它是一致的。

编辑:@mjturner 每个请求的一些额外命令

$ ls -ld /mnt/archive/targetDir
drwxrwxr-x 2 myUser myUser 1064583168 Aug 10 05:07 /mnt/archive/targetDir

$ tune2fs -l /dev/mapper/archive-lvarchive
tune2fs 1.42.10 (18-May-2014)
Filesystem volume name:   <none>
Last mounted on:          /mnt/archive
Filesystem UUID:          af7e7b38-f12a-498b-b127-0ccd29459376
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr dir_index filetype needs_recovery extent 64bit flex_bg sparse_super huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash 
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              289966080
Block count:              4639456256
Reserved block count:     231972812
Free blocks:              1274786115
Free inodes:              256343444
First block:              0
Block size:               4096
Fragment size:            4096
Group descriptor size:    64
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         2048
Inode blocks per group:   128
RAID stride:              128
RAID stripe width:        512
Flex block group size:    16
Filesystem created:       Thu Jun 25 12:05:12 2015
Last mount time:          Mon Aug  3 18:49:29 2015
Last write time:          Mon Aug  3 18:49:29 2015
Mount count:              8
Maximum mount count:      -1
Last checked:             Thu Jun 25 12:05:12 2015
Check interval:           0 (<none>)
Lifetime writes:          24 GB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:           256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      3ea3edc4-7638-45cd-8db8-36ab3669e868
Journal backup:           inode blocks

$ tune2fs -l /dev/sda1
tune2fs 1.42.10 (18-May-2014)
Filesystem volume name:   <none>
Last mounted on:          /mnt/tmp
Filesystem UUID:          10df1bea-64fc-468e-8ea0-10f3a4cb9a79
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash 
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              152621056
Block count:              1220942336
Reserved block count:     61047116
Free blocks:              367343926
Free inodes:              135953194
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      732
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         4096
Inode blocks per group:   256
Flex block group size:    16
Filesystem created:       Thu Jul 23 13:54:13 2015
Last mount time:          Tue Aug  4 04:35:06 2015
Last write time:          Tue Aug  4 04:35:06 2015
Mount count:              3
Maximum mount count:      -1
Last checked:             Thu Jul 23 13:54:13 2015
Check interval:           0 (<none>)
Lifetime writes:          150 MB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:           256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      a266fec5-bc86-402b-9fa0-61e2ad9b5b50
Journal backup:           inode blocks
Run Code Online (Sandbox Code Playgroud)

ste*_*eve 26

dir_index您在目标文件系统上使用的 ext4 功能实现中的错误。

解决方案:重新创建没有 dir_index 的文件系统。或者使用 tune2fs 禁用功能(需要一些注意事项,请参阅相关链接Novell SuSE 10/11:在 ext3 文件系统上禁用 H 树索引,尽管与ext3 相关,但可能需要类似的注意事项。

(get a really good backup made of the filesystem)
(unmount the filesystem)
tune2fs -O ^dir_index /dev/foo
e2fsck -fDvy /dev/foo
(mount the filesystem)
Run Code Online (Sandbox Code Playgroud)

ext4 有一个名为 dir_index 的特性默认启用,它很容易受到散列冲突的影响。

......

ext4 有可能散列其内容的文件名。这提高了性能,但有一个“小”问题:当 ext4 开始填满时,它的哈希表不会增长。相反,它返回 -ENOSPC 或“设备上没有剩余空间”。

  • 发现@steve。不幸的是,关闭 `dir_index` 可能会降低一个目录中 70m 文件的访问性能。 (6认同)
  • 哦,废话,这听起来很像,而且修复起来很痛苦。大概一个月左右可以重新复印。这可以在不丢失内容的情况下完成吗?明天我必须更多地研究 dir_index 等。哇,从来没有想过。 (3认同)
  • 是的。我不需要峰值性能,但是对每个文件进行 fs 搜索会很糟糕。所以现在我正在查看 xfs 或 10k 左右的子文件夹数组。子文件夹是一个合理的解决方案,但是使用 ext4 我仍然冒着冲突的风险。xfs 有同样的问题吗?我读到它使用 B+ 树,但这对我来说意义不大,只要确保永远不会发生碰撞。那里有一个错误信息的世界,我听说过它大大减慢了超过一百万个文件的速度,并声称它没有。 (3认同)
  • 我认为这是一个很好的答案,我想将其标记为这样,但我认为如果我们能够解决问题,而不仅仅是诊断,那就太好了。有谁知道 xfs 是否有这样的问题?我读过混合评论,它可以很好地扩展,或者不超过 1m。 (2认同)

Pet*_*des 8

用于存储大量小文件的优于 ext4 选择的建议:

如果您将文件系统用作对象存储,您可能需要考虑使用专门用于此的文件系统,这可能会损害其他特性。快速谷歌搜索找到Ceph,它似乎是开源的,可以作为 POSIX 文件系统挂载,但也可以通过其他 API 访问。我不知道在不利用复制的情况下是否值得在单个主机上使用。

另一个对象存储系统是OpenStack 的 Swift。它的设计文档说它将每个对象存储为一个单独的文件,元数据在 xattrs 中。这是一篇关于它的文章。 他们的部署指南说他们发现 XFS 为对象存储提供了最佳性能。因此,即使工作负载不是 XFS 最擅长的,但在 RackSpace 进行测试时,它显然比竞争对手更好。可能 Swift 偏爱 XFS,因为 XFS 对扩展属性有良好/快速的支持。如果不需要额外的元数据(或者如果它保存在二进制文件中),那么 ext3/ext4 可能可以在单个磁盘上作为对象存储后端运行。

Swift 为你做复制/负载平衡,并建议你给它在原始磁盘上制作的文件系统,而不是 RAID。它指出它的工作负载对于 RAID5 来说本质上是最坏的情况(如果我们谈论的是写入小文件的工作负载,这是有道理的。XFS 通常不会完全将它们打包,因此您不会获得全条带写入,并且 RAID5 必须进行一些读取以更新奇偶校验条带。Swift 文档还谈到每个驱动器使用 100 个分区。我认为这是一个 Swift 术语,并不是在谈论在每个驱动器上制作 100 个不同的 XFS 文件系统SATA 磁盘。

为每个磁盘运行一个单独的 XFS 实际上是一个巨大的差异。每个磁盘将有一个单独的 XFS 和单独的空闲列表,而不是一个巨大的空闲 inode 映射。此外,它避免了小写的 RAID5 惩罚。

如果您的软件已经构建为直接使用文件系统作为对象存储,而不是通过像 Swift 这样的东西来处理复制/负载平衡,那么您至少可以避免将所有文件放在一个目录中。(我没有看到 Swift 文档说他们如何将文件布置到多个目录中,但我确定他们确实这样做了。)

对于几乎任何普通的文件系统,使用类似的结构都会有所帮助

1234/5678   # nested medium-size directories instead of
./12345678   # one giant directory
Run Code Online (Sandbox Code Playgroud)

大约 10k 个条目是合理的,因此采用分布良好的 4 个对象名称字符并将它们用作目录是一个简单的解决方案。它不必非常平衡。奇怪的 100k 目录可能不会是一个明显的问题,一些空目录也不会。

XFS不适用于大量小文件。它尽其所能,但它针对较大文件的流式写入进行了更优化。不过,它总体上非常适合一般用途。它ENOSPC在其目录索引 (AFAIK)中没有冲突,并且可以处理一个包含数百万个条目的目录。(但最好至少使用一层树。)

Dave Chinner对分配了大量 inode 的 XFS 性能发表了一些评论,导致touch性能缓慢。寻找要分配的空闲 inode 开始花费更多的 CPU 时间,因为空闲 inode 位图变得碎片化。请注意,这不是一个大目录与多个目录的问题,而是整个文件系统上许多使用的 inode 的问题。将文件拆分到多个目录有助于解决一些问题,例如 ext4 在 OP 中阻塞的问题,但不是跟踪可用空间的整个磁盘问题。与 RAID5 上的巨型 XFS 相比,Swift 的每个磁盘的单独文件系统对此有所帮助。

我不知道btrfs是否擅长于此,但我认为可能是。我认为 Facebook 聘用其首席开发人员是有原因的。:P 我见过的一些基准测试,比如解压 Linux 内核源代码,显示 btrfs 做得很好。

我知道reiserfs已针对这种情况进行了优化,但几乎不再维护。我真的不建议使用 reiser4。不过,尝试一下可能会很有趣。但它是迄今为止最不经得起未来考验的选择。我还看到过旧的 reiserFS 性能下降的报告,并且没有好的碎片整理工具。( google filesystem millions of small files,并查看一些现有的 stackexchange 答案。)

我可能遗漏了一些东西,所以最后的建议是:在 serverfault 上询问这个问题! 如果我现在必须选择某些东西,我会说尝试一下 BTRFS,但要确保你有备份。(特别是如果你使用 BTRFS 的内置多磁盘冗余,而不是在 RAID 之上运行它。性能优势可能很大,因为小文件对于 RAID5 来说是个坏消息,除非它是一个以读取为主的工作负载。)