为什么du和ls报告的文件大小之间存在巨大差异?


2

在服务器上,我有一个目录/opt/kafka/data/topics

$ du -hs /opt/kafka/data/topics
52M     /opt/kafka/data/topics

当我像这样的目录tar

$ tar czfv /tmp/topics.tar.gz /opt/kafka/data/topics

我得到一个有意义的文件大小

$ ls -alh /tmp/topics.tar.gz
-rw-r--r-- 1 user user  11M Jan 12 15:15 kafka

但是,当我下载topics.tar.gz到我的本地OS X计算机并提取它时,它占用10GB!


/opt/kafka/data/topics仔细检查服务器上的内容后,我注意到它根据ls它包含许多10MB文件:

$ find /opt/kafka/data -type f -exec ls -alh {} \;
... [output]
-rw-r--r-- 1 user user 10M Jan 12 02:45 /opt/kafka/data/topics/user-entities-KTABLE-REDUCE-STATE-STORE-0000000178-changelog-1/00000000000000000000.index
-rw-r--r-- 1 user user 10M Jan 12 02:45 /opt/kafka/data/topics/user-entities-KSTREAM-KEY-SELECT-0000000123-repartition-2/00000000000000000012.index
... [and many more]

du 报告这些10MB文件中的每一个都是0字节:

$ du -h /opt/kafka/data/topics/user-entities-KTABLE-REDUCE-STATE-STORE-0000000178-changelog-1/00000000000000000000.index
0       /opt/kafka/data/topics/user-entities-KTABLE-REDUCE-STATE-STORE-0000000178-changelog-1/00000000000000000000.index

那么发生了什么?显然我在这里遗漏了一些东西:

  • du报告总计52M。这是有道理的,因为/opt/kafka/data安装的设备只有5GB,df报告它只有2%已满,一切仍然有效。
  • tar将内容gzips到10M。这也是有道理的。
  • ls 据报道,许多文件在磁盘上是10M,当我提取存档时,我得到10GB。
  • du 报告每个相同的文件都是0字节。
  • mount 报告说 /dev/sdc on /opt/kafka/data type ext4 (rw,relatime,data=ordered)

什么都没有增加。是否有某种透明的磁盘压缩我不知道?


源目录中同一文件的多个硬链接?稀疏文件?
Kamil Maciorowski

@KamilMaciorowski没有硬链接; 是的,10MB文件(由报告ls)是稀疏的。它们被报告为0字节du并且确实是空的
Dmitry Minkovsky

tar --sparse创建存档时选项怎么样?有帮助吗?链接
Kamil Maciorowski

帮助什么?问题不在于我创建它时tar很大。焦油很小。问题是在磁盘上,这些10MB稀疏文件似乎占用了0个字节。怎么可能?在文件系统级别有某种压缩吗?为什么ls报告10MB但du报告0字节?
德米特里·明科夫斯基

虽然...我man tar在OS X上确实包含了一个-S提取选项:(x mode only) Extract files as sparse files. For every block on disk, check first if it contains only NULL bytes and seek over it otherwise. This works similiar to the conv=sparse option of dd.这可能会有所帮助。
德米特里·明科夫斯基

Answers:


3

根据评论中的讨论,所有文件都是稀疏的。这种类型的东西实际上在他们第一次处理它时会让很多人感到困惑,所以不要感觉不好。

什么实际发生在这里的报道的价值lsdu

通过一个例子可以很容易地解释这一点。

假设您创建一个空文件,然后从头开始写入1MB数据。生成的文件大小为1MB,磁盘占用1MB。双方lsdu会报告该文件相同的大小1MB。

现在说你创建一个空文件,然后调用seek()将1MB移动到文件中,然后写一个字节。结果文件看起来是1MB + 1字节长,但实际上只有1字节的数据。

在较旧的文件系统上,第二个文件需要花费很长时间才能写入1个字节的数据,因为在写出最后1个字节的实际数据之前,操作系统将忙于写出1MB的空字节。

这种低效率(无论是在创建文件的时间和在磁盘上使用的空间)都是稀疏文件的来源。而不是写出1MB的空字节,支持稀疏文件的操作系统(如所有现代UNIX系统)将在该文件系统的元数据中注释该区域形成0-1MB是空的,然后只存储您编写的那个单字节。结果,文件看起来是1MB + 1字节长,但在磁盘上它只占用1个字节。此外,当某些内容读取该文件时,操作系统注释为空的任何区域将只读回空字节(因此它看起来与第一个文件中的用户程序没有区别)。

这是报告lsdu来自的值之间的差异。默认情况下,ls报告文件的表观大小(即,如果您在第一个字节开始读取文件并一直读到结尾,将读取多少数据),同时du报告文件在磁盘上使用的实际空间(通常不包括操作系统完成的其他节省空间的技巧,如透明压缩)。 在这种情况下du同意,df因为df只报告实际物理上在磁盘上使用的空间量。

通过将该ls -l命令更改为ls -ls,您将获得一个额外的列,显示文件的实际磁盘大小,这应该是一致的du


我不觉得不好,不要担心;)感谢指出-s开关。我会调查一下。
德米特里·明科夫斯基
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.