netatalk パフォーマンスチューニング
WD30EFRX を買った話 の続き。今回は netatalk のパフォーマンスチューニングです。
簡単に済ませるつもりだったのですが、バックエンドのファイルシステムの比較にまで手を出したらえらく時間がかかってしまいました。まだまだ試したいことがあるのですがきりがないので、このあたりでまとめておこうと思います。
なお netatalk はバージョン 3.0.1 が最新版ですが Debian パッケージ を使っている都合で 2.2.2 による検証となっています。
問題
これまで HP MicroServer で運用してきた netatalk 2.2.2 の AFP ボリュームでは、 iPhoto や Aperture のフォトライブラリを置いて使うととにかく遅くて話にならないということが問題になっており、今回のストレージ更新ではこれの改善が目標のひとつです。
調べてみると netatalk の cnid_dbd というデーモンプロセスがボトルネックとなっているらしいことがわかります。このデーモンは AFP ボリュームの全ファイル・ディレクトリに CNID という一意の数値を割り当てるため、 Berkeley DB の環境を各 AFP ボリュームの .AppleDB
というディレクトリに作り、ファイル・ディレクトリの更新があると同時にこの DB も更新しているのでした。
小さなファイル・ディレクトリが多くメタデータの更新が大量にあるようなワークロードでは、本来のファイル・ディレクトリ更新の間に cnid_dbd の fdatasync() が挟まることになります。 AFP ボリュームと CNID DB が同じデバイスに存在する場合、これはひどいパフォーマンスの低下をもたらします。そこでこれらを異なるデバイスに分離するだけで、相当な速度改善が望めるのではと考え、実験してみました。
またついでなので、ファイルシステムについても従来の XFS と EXT4 でどれだけの違いが出るかテストしてみることにしました。
システム
今回の実験に使った OSX マシンは次のようなものです。
- Hardware: MacBook Pro (13-inch, Mid 2009)
- CPU: 2.53GHz Intel Core 2 Duo
- Memory: 8GB 1333MHz DDR3
- NIC: NVIDIA MCP79 Ethernet (1000BASE-T) MTU:1500
- OS: OSX 10.8.2 (Mountain Lion)
netatalk のサーバはいつもの microserver で OpenVZ コンテナとして動かします。
- Hardware: HP ProLiant MicroServer
- CPU: 1.3GHz AMD Athlon™ II Neo N36L Dual-Core Processor
- Memory: 3GB ECC 1333MHz DDR3
- NIC: Broadcom BCM5723 (1000BASE-T) MTU:1500
- HDD: HGST HDP725050GLA360 (/dev/sda)
- HDD: WDC WD30EFRX-68AX9N0 (/dev/sdd, /dev/sde)
- Host OS: Debian 6.0 (squeeze) amd64
- Container OS: Debian 7.0 (wheezy) amd64
準備
まず microserver に 2 台の WD30EFRX を接続し mdadm で最初からデバイスがひとつ欠けた RAID1 ボリュームを 2 つ作成しました。それぞれを XFS と EXT4 で mkfs してマウントします。
microserver# mdadm -C /dev/md/m00 -n2 -l1 /dev/sdd missing microserver# mdadm -C /dev/md/m01 -n2 -l1 /dev/sde missing microserver# cat /proc/mdstat Personalities : [raid1] md125 : active raid1 sdd[0] 2930265424 blocks super 1.2 [2/1] [U_] md126 : active raid1 sde[0] 2930265424 blocks super 1.2 [2/1] [U_]
microserver# mkfs -t xfs -s size=4096 /dev/md/m00 microserver# mkfs -t ext4 /dev/md/m01 microserver# mkdir -p /vol/m00 /vol/m01 microserver# mount /dev/md/m00 /vol/m00 microserver# mount /dev/md/m01 /vol/m01 -o user_xattr
それぞれのボリュームに従来の環境から移行予定のデータ 1.5TB ほどを事前にコピーしておきます。パフォーマンスが悪いほうのボリュームを初期化しもう片方の RAID1 に追加する計画です。
Debian wheezy amd64 の OpenVZ コンテナを用意し netatalk 2.2.2-1 をインストールします。 mkfs したふたつのボリュームを bind mount により /vol/m00
(XFS) および /vol/m01
(EXT4) としてコンテナ内から直接アクセスできるようにしました。
netatalk コンテナ内で cnid_dbd が使う CNID DB 用のディレクトリを用意し /tmp/CNID/
には tmpfs をマウントしておきます。
netatalk# mkdir -p /var/lib/netatalk/CNID /tmp/CNID netatalk# mount -t tmpfs tmpfs /tmp/CNID
最終的には次のような状況となりました。システムの simfs は OpenVZ ホストのシステム HDD (HGST HDP725050GLA360) が割り当てられています。
netatalk# cat /proc/mounts ... /dev/simfs / simfs rw,relatime 0 0 /dev/md126 /vol/m00 xfs rw,relatime,attr2,noquota 0 0 /dev/md125 /vol/m01 ext4 rw,relatime,errors=remount-ro,user_xattr,barrier=1,nodelalloc,data=ordered 0 0 tmpfs /tmp/CNID tmpfs rw,relatime 0 0
netatalk は次のような AppleVolumes でテストしました。
:DEFAULT: options:upriv,usedots dperm:2770 fperm:0660 umask:007 /vol/m00/afp-xfs-default "afp-xfs-default" /vol/m00/afp-xfs-var "afp-xfs-var" dbpath:/var/lib/netatalk/CNID/$v /vol/m00/afp-xfs-tmp "afp-xfs-tmp" dbpath:/tmp/CNID/$v /vol/m01/afp-ext4-default "afp-ext4-default" /vol/m01/afp-ext4-var "afp-ext4-var" dbpath:/var/lib/netatalk/CNID/$v /vol/m01/afp-ext4-tmp "afp-ext4-tmp" dbpath:/tmp/CNID/$v
ファイルシステム 2 種類 (xfs, ext4) と CNID DB 設定 (dbpath) 3 種類の組み合わせで計 6 つの AFP ボリュームを設定しています。 CNID DB 設定の説明は次のとおりです。
-default
は dbpath 設定なし。 CNID DB を AFP ボリューム内に作成します。-tmp
は tmpfs (RAM ディスク) の/tmp/CNID/
に DB を作成してみます。-var
は AFP ボリュームとは異なる HDD の/var/lib/netatalk/CNID/
に DB を作成してみます。
これらのボリュームのためのディレクトリを作成しパーミッションを適切に設定しておきます。
netatalk# mkdir -p /vol/m00/afp-xfs-default netatalk# mkdir -p /vol/m00/afp-xfs-var netatalk# mkdir -p /vol/m00/afp-xfs-tmp netatalk# mkdir -p /vol/m01/afp-ext4-default netatalk# mkdir -p /vol/m01/afp-ext4-var netatalk# mkdir -p /vol/m01/afp-ext4-tmp netatalk# chown yaegashi.yaegashi /vol/m0*/afp-* netatalk# chmod 2775 /vol/m0*/afp-*
netatalk をスタートしたあとに OSX 側からマウントしてみて、それぞれのボリュームに対する CNID DB の Berkeley DB 環境が .AppleDB
ディレクトリで適切に初期化されていることを確認します。
netatalk# /etc/init.d/netatalk start Starting Netatalk services (this will take a while): cnid_metad afpd. netatalk# ls -l /tmp/CNID/afp-xfs-tmp/.AppleDB/ 合計 6396 -rw-r----- 1 root root 24576 1月 2 23:15 __db.001 -rw-r----- 1 root root 647168 1月 2 23:15 __db.002 -rw-r----- 1 root root 10493952 1月 2 23:15 __db.003 -rw-r----- 1 root root 163840 1月 2 23:15 __db.004 -rw-r----- 1 root root 9158656 1月 2 23:15 __db.005 -rw-r----- 1 root root 40960 1月 2 23:15 __db.006 -rw-r--r-- 1 root root 16384 1月 2 23:15 cnid2.db -rw-r--r-- 1 root root 19 1月 2 23:15 db_errlog -rw-r--r-- 1 root root 0 1月 2 23:15 lock -rw-r----- 1 root root 10485760 1月 2 23:15 log.0000000001
OSX 側で df
するとこのようになりました。
osx% df Filesystem 512-blocks Used Available Capacity iused ifree %iused Mounted on ... //yaegashi@netatalk._afpovertcp._tcp.local/afp-ext4-default 5475541352 2689097752 2786443600 50% 336137217 348305450 49% /Volumes/afp-ext4-default //yaegashi@netatalk._afpovertcp._tcp.local/afp-ext4-tmp 5475541352 2689097752 2786443600 50% 336137217 348305450 49% /Volumes/afp-ext4-tmp //yaegashi@netatalk._afpovertcp._tcp.local/afp-ext4-var 5475541352 2689097752 2786443600 50% 336137217 348305450 49% /Volumes/afp-ext4-var //yaegashi@netatalk._afpovertcp._tcp.local/afp-xfs-default 5857669264 2738758232 3118911032 47% 342344777 389863879 47% /Volumes/afp-xfs-default //yaegashi@netatalk._afpovertcp._tcp.local/afp-xfs-tmp 5857669264 2738758232 3118911032 47% 342344777 389863879 47% /Volumes/afp-xfs-tmp //yaegashi@netatalk._afpovertcp._tcp.local/afp-xfs-var 5857669264 2738758232 3118911032 47% 342344777 389863879 47% /Volumes/afp-xfs-var
bonnie++ on netatalk
最初に XFS と EXT4 の基本的な性能差を見るため netatalk コンテナで bonnie++ を走らせてみました。
- Sequential Output: XFS の性能が優れているようです。
- Sequential Input: あまり性能の差がないようです。
- Sequential/Random Create: EXT4 のほうがだんとつに速くなっています。 XFS は mkfs のオプション 次第ではこれよりさらに性能が劣化します。
マウントオプションをいじるともう少し速度を向上させることができるのですが、今回のテストはこれをベースに行いました。
ファイルコピー(小)
最初に OSX マシンからのファイル・ディレクトリコピーのテストをします。
テストに使うのは RX100.aplibrary
という Aperture のフォトライブラリです。総容量 8GB でファイル・ディレクトリの数が約 10,000 あり、サイズの小さなファイルもかなり多いツリーになっています。
osx% du -hs RX100.aplibrary 7.9G RX100.aplibrary osx% find RX100.aplibrary | wc -l 10027
これを順番に各 AFP ボリュームのマウントポイントに rsync してかかる時間を計測します。次のようなスクリプトを走らせました。
#!/bin/sh -x for i in xfs ext4; do for j in default tmp var; do time rsync -avP RX100.aplibrary /Volumes/afp-$i-$j done done
結果:
ファイルコピー(小) | 経過時間(s) | 速度(MB/s) |
---|---|---|
afp-xfs-default | 1566.561 | 5.485 |
afp-xfs-tmp | 673.519 | 13.964 |
afp-xfs-var | 911.855 | 9.548 |
afp-ext4-default | 1069.797 | 7.980 |
afp-ext4-tmp | 347.289 | 25.583 |
afp-ext4-var | 696.824 | 12.334 |
- CNID DB: 予想通り dbpath を AFP ボリュームとは異なるデバイスに置くと大きく性能が改善することがわかりました。特に default と tmpfs とでは 2 倍から 3 倍の差がついています。
- ファイルシステム: EXT4 が XFS に比べてかなり速いことがわかりました。
ファイルコピー(大)
今度は次のようにして作った 100MB から 1GB まで 10 個のファイルを rsync でコピーしてみます。
osx% mkdir images osx% for i in $(seq 10); do dd if=/dev/urandom of=images/$i.img bs=100000000 count=$i; done osx% du -h images 5.1G images
結果:
ファイルコピー(大) | 経過時間(s) | 速度(MB/s) |
---|---|---|
afp-xfs-default | 107.161 | 50.697 |
afp-xfs-tmp | 103.374 | 53.147 |
afp-xfs-var | 104.323 | 52.638 |
afp-ext4-default | 115.430 | 47.216 |
afp-ext4-tmp | 119.226 | 46.030 |
afp-ext4-var | 200.626 | 45.273 |
- CNID DB: メタデータ操作が少ないため差はほとんどありませんでした。
- ファイルシステム: XFS が 52MB/s 程度に対して EXT4 が 46MB/s 程度と bonnie++ の計測結果に一致する性能の違いが出ています。
ファイル削除
最後に、これまでコピーしたファイルを OSX から削除してみます。これも単純に次のようなスクリプトを走らせて rm -rf
にかかる時間を計測します。
#!/bin/sh -x for i in xfs ext4; do for j in default tmp var; do time rm -rf /Volumes/afp-$i-$j/* done done
結果:
ファイル削除 | 経過時間(s) |
---|---|
afp-xfs-default | 632.086 |
afp-xfs-tmp | 129.763 |
afp-xfs-var | 229.681 |
afp-ext4-default | 298.121 |
afp-ext4-tmp | 47.351 |
afp-ext4-var | 202.275 |
- CNID DB: tmp とそれ以外との性能の差がさらに顕著に出ています。メタデータ操作のみでデータ転送をほとんど伴わないからでしょう。
- ファイルシステム: XFS と EXT4 の差も広がっています。
bonnie++ 1.96
OSX 側のベンチマークソフトとして bonnie++ を走らせてみたかったのですが、 OSX の bonnie++ 1.96 は AFP ボリュームでは途中でこけて動きませんでした。
osx% bonnie++ -d /Volumes/afp-xfs-default Writing a byte at a time...done Writing intelligently...done Rewriting...done Reading a byte at a time...done Reading intelligently...done start 'em...done...done...done...done...done... Create files in sequential order...done. Stat files in sequential order...done. Delete files in sequential order...Bonnie: drastic I/O error (rmdir): Directory not empty Cleaning up test directory after error.
検索すると似たような報告がちらほら見つかるので bonnie++ のバグかもしれませんが、今回は深追いせずあきらめました。
PostMark 1.51
PostMark は小さなファイル・ディレクトリを大量に作成・削除するフリーなベンチマークソフトで、これは Web サーバとかメールサーバなどのワークロードを再現しているそうです。 Homebrew でインストールできます。
次のようなファイル postmark.cfg
を用意して実行してみました。
set number 5000 set transactions 5000 set buffering false set location /Volumes/afp-ext4-default show run set location /Volumes/afp-ext4-tmp show run set location /Volumes/afp-ext4-var show run set location /Volumes/afp-xfs-default show run set location /Volumes/afp-xfs-tmp show run set location /Volumes/afp-xfs-var show run
osx% postmark postmark.cfg PostMark v1.51 : 8/14/01 Reading configuration from file 'postmark.cfg' Current configuration is: The base number of files is 5000 Transactions: 5000 Files range between 500 bytes and 9.77 kilobytes in size Working directory: /Volumes/afp-ext4-default (weight=1) Block sizes are: read=512 bytes, write=512 bytes Biases are: read/append=5, create/delete=5 Not using Unix buffered file I/O Random number generator seed is 42 Report format is verbose. Creating files...Done Performing transactions..........Done Deleting files...Done Time: 508 seconds total 193 seconds of transactions (25 per second) Files: 7454 created (14 per second) Creation alone: 5000 files (27 per second) Mixed with transactions: 2454 files (12 per second) 2524 read (13 per second) 2476 appended (12 per second) 7454 deleted (14 per second) Deletion alone: 4908 files (37 per second) Mixed with transactions: 2546 files (13 per second) Data: 13.52 megabytes read (27.26 kilobytes per second) 42.12 megabytes written (84.91 kilobytes per second)
結果:
PostMark 1.51 | txn(/s) | create(/s) | read(/s) | append(/s) | delete(/s) |
---|---|---|---|---|---|
afp-xfs-default | 10 | 6 | 5 | 5 | 6 |
afp-xfs-tmp | 33 | 16 | 16 | 16 | 16 |
afp-xfs-var | 20 | 12 | 10 | 10 | 12 |
afp-ext4-default | 25 | 14 | 13 | 12 | 14 |
afp-ext4-tmp | 119 | 82 | 60 | 58 | 82 |
afp-ext4-var | 40 | 25 | 20 | 20 | 25 |
- ファイルコピー(小)およびファイル削除と同じ傾向が出ています。
Blackmagic Disk Speed Test 2.2
Blackmagic Disk Speed Test は映像系のストレージ性能の計測に特化した無料のベンチマークソフトで、 AFP ボリュームで 1000BASE-T のワイヤースピードに迫る値が出せるありがたいソフトです。 Mac App Store からインストールできます。
結果:
Disk Speed Test 2.2 | WRITE (MB/s) | READ (MB/s) |
---|---|---|
afp-xfs-default | 103.5 | 109.7 |
afp-xfs-tmp | 105.1 | 109.6 |
afp-xfs-var | 105.5 | 110.0 |
afp-ext4-default | 88.5 | 108.0 |
afp-ext4-tmp | 88.4 | 108.3 |
afp-ext4-var | 87.3 | 107.6 |
- ファイルコピー(大)と同様の傾向が出ているように見えます。
- CNID DB: メタデータ操作がないため差が見られませんでした。
- ファイルシステム: EXT4 の WRITE でファイルシステムのスループットと見られる 88MB/s という値が出ています。それ以外では 1000BASE-T の通信速度に達してしまっているようで、ファイルシステム本来のスループットは計測できませんでした。
まとめ
netatalk において AFP ボリュームと CNID DB (.AppleDB
ディレクトリ) を別デバイスに分けることでメタデータ更新性能が大きく向上することがわかりました。
CNID DB を tmpfs (RAM ディスク) に置くと非常に高速になりますが、システムが再起動したときに消えてしまうので、現実的には /var
のような普通のストレージに割り当てることになるでしょう。ここを SSD にするといいかもしれまえせん。
netatalk 2.2 までではデフォルトで AFP ボリュームと同じ場所に CNID DB を作ってしまいます。 マニュアル の例にもありますが AppleVolumes のデフォルト設定として次のように dbpath を指定するのがよいでしょう。
:DEFAULT: options:upriv,usedots dbpath:/var/lib/netatalk/CNID/$v dperm:0775 fperm:0664
netatalk 3.0 以降のデフォルトでは CNID DB を :STATEDIR:/netatalk/CNID/$v/
に作成する設定 (vol dbpath) になっていますので、特になにもする必要はないようです。バイナリパッケージではビルドの設定を確認してください。
バックエンドのファイルシステムとして XFS と EXT4 を試しましたが、それぞれが評判通りの特性を示す結果となりました。
I/O WRITE | I/O READ | メタデータ更新性能 | |
---|---|---|---|
XFS | 高い | 高い | 非常に低い |
EXT4 | そこそこ | 高い | 非常に高い |
どちらを使うべきかはなかなか悩ましい選択といえます。動画など 10MB 単位のファイルのみであれば迷わず XFS ですが、大量の小さなファイルを大量に扱う必要があるならば、多少の I/O スループットを犠牲にしてでも EXT4 のメタデータ更新性能をとるべきかもしれません。
OSX ではアプリケーションがパッケージやバンドルのようなデータ形式 (実体はただのディレクトリとファイル) をよく作るため、そのようなケースに該当することもあるのではないでしょうか。
2013/01/03 17:52:00 JST