在服务器上,我有一个目录/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
将内容压缩到 10M。这也是有道理的。ls
报告称许多文件在磁盘上的大小为 10M,而当我提取档案时,我得到了 10GB。du
报告称这些相同的文件都是 0 字节。mount
报道称/dev/sdc on /opt/kafka/data type ext4 (rw,relatime,data=ordered)
什么都说不通。是否存在某种我不知道的透明磁盘压缩?
答案1
根据评论中的讨论,所有文件都很稀疏。这种事情实际上让很多人在第一次处理时感到困惑,所以不要感到难过。
ls
和报告的值这里实际上发生了什么du
?
用一个例子就可以很容易地解释这一点。
假设您创建一个空文件,然后从头开始向其中写入 1MB 的数据。生成的文件大小为 1MB,占用 1MB 磁盘空间。ls
和都du
将报告该文件的相同大小 1MB。
现在假设你创建一个空文件,然后调用seek()
将 1MB 移入文件,然后写入一个字节。生成的文件看起来长度为 1MB + 1 字节,但实际上其中只有 1 字节的数据。
在较旧的文件系统上,第二个文件需要花费很长时间才能写入 1 字节的数据,因为操作系统在写出最后 1 字节的实际数据之前会忙于写出 1MB 的空字节。
这种低效率(无论是在创建文件的时间方面,还是在磁盘上占用的空间方面)正是稀疏文件出现的原因。支持稀疏文件的操作系统(如所有现代 UNIX 系统)不会写出 1MB 的空字节,而是会在文件系统的元数据中注释 0-1MB 区域为空,然后只存储您写入的单个字节。因此,文件看起来是 1MB + 1 字节长,但在磁盘上它只占用 1 个字节。此外,当有人读取该文件时,操作系统注释为空的任何区域都只会读回为空字节(因此对于用户程序来说,它看起来与第一个文件没有什么不同)。
ls
这就是和报告的值之间的差异的来源du
。默认情况下,ls
报告文件的表观大小(即,如果从第一个字节开始读取文件并一直读到最后,将读取多少数据),而du
报告文件在磁盘上实际使用的空间(通常不包括操作系统执行的其他节省空间的技巧,如透明压缩)。 在这种情况下du
同意因为只报告磁盘上实际物理使用的空间量。df
df
通过将该ls -l
命令更改为ls -ls
,您将获得一个额外的列,显示文件的实际磁盘大小,该列应与 一致du
。