12月 042015
 

この記事はVarnish Cache Advent Calendar 2015の3日目の記事になります。

Varnishは4.0まではfile-storageを使用する場合は特にpre-allocateをしないため、フラグメントによるパフォーマンス低下を防ぐためにdd(1)を使って先に確保してしまうのを推奨していました。
4.1でも事前確保するのを推奨しているのですが、実はbetaまではfallocateを利用してpre-allocateするようになっていました。
正式版ではこの機能はext4限定になってしまい他のファイルシステムではdisableになりました。
何故かxfsだと既に領域を確保しているにもかかわらずfallocateを使おうとするとENOSPCがでるケースがあったためです。
このバグの報告をしたのは自分なのですが、その際にfallocateについて調べてたら割と興味深い動きだったので今回書きます。

fallocateとは
すごく簡単にいうとめっちゃ高速にディスク領域の割当ができます。
どれぐらい速いかというと


# time fallocate -l 10GB varnish_storage.bin

real    0m0.001s
user    0m0.000s
sys     0m0.001s


と気にならないレベルです。
割と便利だと思います。

fallocateの不思議な動き
xfsとext4でfallocateの動きを確認した際に以下のような動きをしました。

xfs-fallocate


root@varnish-trunk:/mnt/xfs# df -T .
Filesystem     Type 1K-blocks  Used Available Use% Mounted on
/dev/xvdh      xfs   15718400 32928  15685472   1% /mnt/xfs
root@varnish-trunk:/mnt/xfs# fallocate -l 10GB varnish_storage.bin
root@varnish-trunk:/mnt/xfs# df -T .
Filesystem     Type 1K-blocks    Used Available Use% Mounted on
/dev/xvdh      xfs   15718400 9798556   5919844  63% /mnt/xfs
root@varnish-trunk:/mnt/xfs# fallocate -l 10GB varnish_storage.bin
fallocate: varnish_storage.bin: fallocate が失敗: デバイスに空き領域がありません
root@varnish-trunk:/mnt/xfs# ls -ltah varnish_storage.bin
-rw-r--r-- 1 root root 9.4G 12月  3 23:55 varnish_storage.bin

ext4-fallocate


root@varnish-trunk:/mnt/ext4# df -T .
Filesystem     Type 1K-blocks  Used Available Use% Mounted on
/dev/xvdi      ext4  15350768 38384  14509568   1% /mnt/ext4
root@varnish-trunk:/mnt/ext4# fallocate -l 10GB varnish_storage.bin
root@varnish-trunk:/mnt/ext4# df -T .
Filesystem     Type 1K-blocks    Used Available Use% Mounted on
/dev/xvdi      ext4  15350768 9804016   4743936  68% /mnt/ext4
root@varnish-trunk:/mnt/ext4# fallocate -l 10GB varnish_storage.bin
root@varnish-trunk:/mnt/ext4# ls -ltah varnish_storage.bin
-rw-r--r-- 1 root root 9.4G 12月  3 23:56 varnish_storage.bin

なぜかxfsは同じ容量を確保しようとしてるのに失敗する。

xfs-stat


root@varnish-trunk:/mnt/xfs# fallocate -l 1GB varnish_storage.bin
root@varnish-trunk:/mnt/xfs# stat varnish_storage.bin
  File: `varnish_storage.bin'
  Size: 1000000000      Blocks: 1953128    IO Block: 4096   通常ファイル
Device: ca70h/51824d    Inode: 131         Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2015-12-03 23:58:42.851567000 +0900
Modify: 2015-12-03 23:58:47.475567000 +0900
Change: 2015-12-03 23:58:47.475567000 +0900
 Birth: -
root@varnish-trunk:/mnt/xfs# fallocate -l 1GB varnish_storage.bin
root@varnish-trunk:/mnt/xfs# stat varnish_storage.bin
  File: `varnish_storage.bin'
  Size: 1000000000      Blocks: 1953128    IO Block: 4096   通常ファイル
Device: ca70h/51824d    Inode: 131         Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2015-12-03 23:58:42.851567000 +0900
Modify: 2015-12-03 23:59:15.123567000 +0900★変わった
Change: 2015-12-03 23:59:15.123567000 +0900★変わった
 Birth: -

ext4-stat


root@varnish-trunk:/mnt/ext4# fallocate -l 1GB varnish_storage.bin
root@varnish-trunk:/mnt/ext4# stat varnish_storage.bin
  File: `varnish_storage.bin'
  Size: 1000000000      Blocks: 1953136    IO Block: 4096   通常ファイル
Device: ca80h/51840d    Inode: 12          Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2015-12-03 23:59:35.871567000 +0900
Modify: 2015-12-03 23:59:35.871567000 +0900
Change: 2015-12-03 23:59:35.871567000 +0900
 Birth: -
root@varnish-trunk:/mnt/ext4# fallocate -l 1GB varnish_storage.bin
root@varnish-trunk:/mnt/ext4# stat varnish_storage.bin
  File: `varnish_storage.bin'
  Size: 1000000000      Blocks: 1953136    IO Block: 4096   通常ファイル
Device: ca80h/51840d    Inode: 12          Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2015-12-03 23:59:35.871567000 +0900
Modify: 2015-12-03 23:59:35.871567000 +0900★変わってない
Change: 2015-12-03 23:59:35.871567000 +0900
 Birth: -

xfsは同じサイズでfallocateを叩くとタイムスタンプが変わる。

xfs-filefrag


root@varnish-trunk:/mnt/xfs# fallocate -l 1GB varnish_storage.bin
root@varnish-trunk:/mnt/xfs# filefrag -v varnish_storage.bin |md5sum
8a5e67e82aa00af5af01c6d825bd8142  -
root@varnish-trunk:/mnt/xfs# fallocate -l 1GB varnish_storage.bin
root@varnish-trunk:/mnt/xfs# filefrag -v varnish_storage.bin |md5sum
8a5e67e82aa00af5af01c6d825bd8142  -

ext4-filefrag


root@varnish-trunk:/mnt/ext4# filefrag -v varnish_storage.bin |md5sum
9785097e3ce0e6eb3dd703fbd54e5d69  -
root@varnish-trunk:/mnt/ext4# fallocate -l 1GB varnish_storage.bin
root@varnish-trunk:/mnt/ext4# filefrag -v varnish_storage.bin |md5sum
9785097e3ce0e6eb3dd703fbd54e5d69  -

両方共、physical_offsetに変化なし
ちなみにext4の場合は割とフラグメントしますがxfsの場合はあまりしませんでした。
(10GB確保時にext4=12~50extents xfs=3~5extents)

これらを見てみると恐らくxfsは毎回空き容量と確保したい容量を付きあわせていて(既にallocateされてる容量は無視?)
ext4は最初にコマンド実施が必要かどうかをチェックしてるように見えます。
なんでこうなるのかxfsのコードを少し追ったのですが流石にキツかったので途中で諦めました。

まとめとか
fallocateは速くて便利なんでdd使ってpre-allocateしてる人はfallocate使うと幸せになれると思います(とは言えext3とかはサポートしてませんが)
そしてvarnish4.1をext4で動かす場合は内部でfallocateするので、今まで手動でやっていたpre-allocateは不要です。
もし、自分でfallocateを使ったコードを書く場合は実行前にfstat等で実際に使用している容量を調べるなどして使うと良いと思います。


 Posted by at 12:43 AM

  2 Responses to “file-storageのpre-allocateについて(fallocate)”

  1. そのまま利用してたら謎のIO Waitが発生し悩まされてましたが、こちらで解決しました。
    これはどのバージョンを利用したとしても、XFSの場合はDDで全領域割り当てをしないといけないということでしょうか?

  2. いいえddである必要はなくfallocateで問題無いです。
    ただxfsの場合は既に容量が確保されているケースでも確保するための残容量がない(ENOSPC)が返されるので注意しましょうぐらいです。
    また、なおpre-allocate自体は特に必須ではないのと(パフォーマンスを考える時は推奨)
    やる場合はファイルシステムにかかわらずにやって置くとよいでしょう。
    記事でも触れたとおり4.1.xでext4で動く場合はVarnish側でやるので特に必要はありません。
    なお、他のfsでやる場合でも起動の度にやる必要はなく、一度やればOKです。

    また4.0.xではpre-allocate関連ではないですが容量計算に問題があって
    指定ストレージサイズが空き容量を超えるサイズを指定していると
    既にサイズが確保されている場合(pre-allocate)に起動失敗するバグがありますのでご注意ください。(4.0.3でも起きるはず)
    https://www.varnish-cache.org/trac/ticket/1682

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)