web-dev-qa-db-ja.com

duとlsによって報告されたファイルサイズの間に大きな不一致があるのはなぜですか?

サーバー上に、ディレクトリ_/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は合計5200万を報告します。 _/opt/kafka/data_がマウントされているデバイスはわずか5GBであるため、これは理にかなっています。dfは、2%しか使用されておらず、すべてがまだ機能していると報告しています。
  • tarはコンテンツを10Mにgzipします。これも理にかなっています。
  • lsは、ファイルの多くがディスク上で10Mであり、アーカイブを抽出すると10GBになると報告しています。
  • duは、これらの同じファイルがそれぞれ0バイトであることを報告します。
  • mount/dev/sdc on /opt/kafka/data type ext4 (rw,relatime,data=ordered)を報告します

何も足し合わない。私が気付いていないある種の透過的なオンディスク圧縮はありますか?

2

コメントでの議論に基づいて、すべてのファイルはまばらです。この種のことは、実際に最初に扱うときに多くの人を混乱させるので、気分が悪くなることはありません。

lsduによって報告された値で実際にここで何が起こっているのでしょうか。

これは例で最も簡単に説明されます。

空のファイルを作成し、最初から1MBのデータをそのファイルに書き込むとします。結果のファイルのサイズは1MBになり、ディスク上で1MBを占有します。 lsduはどちらも、ファイルに対して同じ1MBのサイズを報告します。

代わりに、空のファイルを作成し、seek()を呼び出して1MBをファイルに移動し、1バイトを書き込むとします。結果のファイルは1MB + 1バイトの長さのように見えますが、実際には1バイトのデータしかありません。

古いファイルシステムでは、OSが実際のデータの最後の1バイトを書き出す前に、1MBのヌルバイトを書き出すのに忙しいため、2番目のファイルがその1バイトのデータを書き込むのに非常に長い時間がかかりました。

この非効率性(ファイルの作成時間とディスクで使用されるスペースの両方)がスパースファイルの出番です。1MBのヌルバイトを書き出す代わりに、スパースファイルをサポートするOS(すべての最新のUNIXシステムと同様)はそのファイルシステムのメタデータに、0〜1MBの領域が空であることを通知し、書き込んだ1バイトのみを格納します。その結果、ファイルの長さは1MB + 1バイトのように見えますが、ディスク上では1バイトしか使用しません。さらに、何かがそのファイルを読み取ろうとすると、OSが空として注釈を付けた領域は、nullバイトとして読み戻されます(したがって、最初のファイルのユーザープログラムと同じように見えます)。

これは、lsduによって報告された値の間の不一致の原因です。デフォルトでは、lsはファイルの見かけのサイズ(つまり、最初のバイトからファイルの読み取りを開始し、最後まで読み取った場合に読み取るデータ量)を報告しますが、duはディスクで使用される実際のスペースを報告します。ファイル(通常、透過圧縮など、OSによって実行される他のスペース節約のトリックは含まれません)。 duは、ディスク上で実際に物理的に使用されているスペースの量のみを報告するため、この場合、dfdfと一致します。

それを変更することによってls -lコマンドからls -ls、ファイルの実際のディスク上のサイズを示す追加の列が表示されます。これはduと一致する必要があります。

5