背景
- HDD * 8でRAID-6を組んで32TiBになったディスクアレイ上に構成したファイルシステムにfioでベンチマークをしたい
- HDD単体の外周内周?については過去にやっているし、RAID6に対しても構築時にやったので、新規性が欲しいと考えた
- ストレージ系のベンチマークは全く使っていない状態に対して行うことがほとんどなので、空きがある状態(効率的に扱える状態)であったり、断片化が起きてない状態で実施するので、そうでない場合の性能も見たい
- RAID6でも物理的に効率的に使えない状態での性能をちょっと見てみたかった
- そのためにはまず内周と外周にファイルを置く必要がある
- やっていて気付いたが、ext4は内部でextentという領域をいくつも使って1つのファイルを管理しているらしい
- extentをより多く使っている状態(断片化?)が起きていると性能に影響がでるのでは?
つまり、
RAID6でHDDの内周外周の影響と、断片化が起きているファイルに対してベンチマークをとってみよう
ということです。
やったこと
ファイルを大量に作る
まず素直な考え方として「データを限られた領域に敷き詰める問題」を与えられた場合、配置する順序は多分バラバラではなくて先頭から順番に詰めて作るはずです。きっとそうに違いない。これを信じて順番にファイルを作ってみましょう。最初あたりに作られたファイルは先端、最後あたりに作られたファイルは終端にあるはずです。
その為にはファイルをたくさん作る必要があります。やっていきましょう。
ddで地道に作ると大変時間がかかりますが、fallocateであればすぐに作れます。
今回はベンチマークで10GiBのファイルを用意したいので FILE_SIZE=10GiB とします。
10GiBは結構極端なんですが、そうでもないとfioの処理がすぐに終わってしまうのでそれっぽい結果が取れません。
#!/bin/bash # 変数設定 MOUNT_POINT="/mnt" FILEPATH="$MOUNT_POINT/dummy_file" FILE_SIZE=10GiB INDEX=0 time while fallocate -l $FILE_SIZE "$FILEPATH.$(printf "%08d" $INDEX)"; do echo -n "." INDEX=$((INDEX + 1)) done echo CREATED $INDEX files.
前半はサクサク進みましたが、後半は結構時間がかかります。
$ ls -l /mnt total 35021341872 -rw-r--r--. 1 root root 10737418240 Jun 9 21:38 dummy_file.00000000 -rw-r--r--. 1 root root 10737418240 Jun 9 21:38 dummy_file.00000001 -rw-r--r--. 1 root root 10737418240 Jun 9 21:38 dummy_file.00000002 (中略) -rw-r--r--. 1 root root 10737418240 Jun 9 21:46 dummy_file.00003323 -rw-r--r--. 1 root root 10737418240 Jun 9 21:46 dummy_file.00003324 -rw-r--r--. 1 root root 10737418240 Jun 9 21:46 dummy_file.00003325 -rw-r--r--. 1 root root 10737418240 Jun 9 21:46 dummy_file.00003326 -rw-r--r--. 1 root root 10737418240 Jun 9 21:47 dummy_file.00003327 -rw-r--r--. 1 root root 10737418240 Jun 9 21:48 dummy_file.00003328 -rw-r--r--. 1 root root 10737418240 Jun 9 21:48 dummy_file.00003329 -rw-r--r--. 1 root root 10737418240 Jun 9 21:49 dummy_file.00003330 -rw-r--r--. 1 root root 10737418240 Jun 9 21:50 dummy_file.00003331 -rw-r--r--. 1 root root 10737418240 Jun 9 21:51 dummy_file.00003332 -rw-r--r--. 1 root root 10737418240 Jun 9 21:51 dummy_file.00003333 -rw-r--r--. 1 root root 10737418240 Jun 9 21:52 dummy_file.00003334 -rw-r--r--. 1 root root 10737418240 Jun 9 21:53 dummy_file.00003335 -rw-r--r--. 1 root root 10737418240 Jun 9 21:54 dummy_file.00003336 -rw-r--r--. 1 root root 10737418240 Jun 9 21:54 dummy_file.00003337 -rw-r--r--. 1 root root 10737418240 Jun 9 21:55 dummy_file.00003338 -rw-r--r--. 1 root root 9600471040 Jun 9 21:56 dummy_file.00003339
いっぱい作れました。だいたい18分くらいでしょうか。後半は残りの空きスペースのやりくりで辛くなっていたようです。
容量を使い切れたか確認してみましょう。
$ df /mnt Filesystem 1K-blocks Used Available Use% Mounted on /dev/md127 35021358392 35021342008 0 100% /mnt
少し空きがあるがこれは単純に10GiBに満たない空きだからです。
まずは敷き詰められたと言ってもいいでしょう。
ファイルの数を得る
ls -U "ディレクトリパス" | wc -l で得られます。
3340ファイルぐらいであればどういうとり方でも誤差のようです。
$ time ls -U "$MOUNT_POINT" | wc -l 3340 real 0m0.004s user 0m0.000s sys 0m0.005s $ time find "$MOUNT_POINT" -maxdepth 1 -type f | wc -l 3340 real 0m0.005s user 0m0.001s sys 0m0.005s
作られているファイルの位置が先端か終端っぽいか確認したい
ファイルの位置なんてどうやって確認するんや?というのがあります。
それにはfilefrag -v "ファイルパス"を使います。
$ filefrag -v /mnt/dummy_file.00000000 Filesystem type is: ef53 File size of /mnt/dummy_file.00000000 is 10737418240 (2621440 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 98303: 8814592.. 8912895: 98304: unwritten 1: 98304.. 589823: 8945664.. 9437183: 491520: 8912896: unwritten 2: 589824.. 1081343: 9469952.. 9961471: 491520: 9437184: unwritten 3: 1081344.. 1572863: 9994240.. 10485759: 491520: 9961472: unwritten 4: 1572864.. 2064383: 10518528.. 11010047: 491520: 10485760: unwritten 5: 2064384.. 2260991: 11042816.. 11239423: 196608: 11010048: unwritten 6: 2260992.. 2549759: 11245568.. 11534335: 288768: 11239424: unwritten 7: 2549760.. 2621439: 11567104.. 11638783: 71680: 11534336: last,unwritten,eof /mnt/dummy_file.00000000: 8 extents found
filefrag -vの読み方として、今回はext(extent)の数とphysical_offsetに注目します。
上記の 00000000は、8個のextentというブロックの集まりのようなものがあり、概ねoffset値が小さいことから先頭のほうに集中しているようです。つまり先頭の大体7個ぐらいの領域に10GiB分のデータが書き込まれているわけです。それでも色々やってたので8,814,592 block目から、というのは全然先頭ではないのでは…という感じですが、全体は 8,790,585,600 blockあるので、8,814,592 block目というのは全体の0.1%ぐらいの位置といえます。先頭の方といえるでしょう。
unwrittenとなっているのは、fallocateで領域を確保しただけだからですね。こうやって書き込まれてない領域は後で初期化するということをやります。(読み出し時に\0で埋めてくれることでしょう)
次は作られた3340個のうちの、半分の1670個目ぐらいのを見てみましょう。
$ filefrag -v /mnt/dummy_file.00001670 Filesystem type is: ef53 File size of /mnt/dummy_file.00001670 is 10737418240 (2621440 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 272383: 4413708288..4413980671: 272384: unwritten 1: 272384.. 763903: 4414013440..4414504959: 491520: 4413980672: unwritten 2: 763904.. 1255423: 4414537728..4415029247: 491520: 4414504960: unwritten 3: 1255424.. 1746943: 4415062016..4415553535: 491520: 4415029248: unwritten 4: 1746944.. 2238463: 4415586304..4416077823: 491520: 4415553536: unwritten 5: 2238464.. 2621439: 4416110592..4416493567: 382976: 4416077824: last,unwritten,eof /mnt/dummy_file.00001670: 6 extents found
extents の数が6個と少ないですが、offsetは大きく増加してますね。値が大きすぎてよくわからないですが。これも後で確認してみましょう。
$ filefrag -v /mnt/dummy_file.00003339 | head Filesystem type is: ef53 File size of /mnt/dummy_file.00003339 is 9600471040 (2343865 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 2015: 8180496416..8180498431: 2016: unwritten 1: 2016.. 2047: 8152186592..8152186623: 32: 8180498432: unwritten 2: 2048.. 4063: 8181020704..8181022719: 2016: 8152186624: unwritten 3: 4064.. 4095: 8152186624..8152186655: 32: 8181022720: unwritten 4: 4096.. 6111: 8181544992..8181547007: 2016: 8152186656: unwritten 5: 6112.. 6143: 8152186656..8152186687: 32: 8181547008: unwritten 6: 6144.. 8159: 8182069280..8182071295: 2016: 8152186688: unwritten $ filefrag -v /mnt/dummy_file.00003339 | tail 2279: 2334688.. 2334719: 8786573408..8786573439: 32: 8787623936: unwritten 2280: 2334720.. 2336735: 8788146208..8788148223: 2016: 8786573440: unwritten 2281: 2336736.. 2336767: 8786573440..8786573471: 32: 8788148224: unwritten 2282: 2336768.. 2338783: 8788670496..8788672511: 2016: 8786573472: unwritten 2283: 2338784.. 2338815: 8786573472..8786573503: 32: 8788672512: unwritten 2284: 2338816.. 2340831: 8789194784..8789196799: 2016: 8786573504: unwritten 2285: 2340832.. 2340863: 8786573504..8786573535: 32: 8789196800: unwritten 2286: 2340864.. 2342879: 8789719072..8789721087: 2016: 8786573536: unwritten 2287: 2342880.. 2343864: 8786573536..8786574520: 985: 8789721088: last,unwritten,eof /mnt/dummy_file.00003339: 2288 extents found
中間までは6~8個ぐらいで大して断片化はなかったんですが、終わりのほうが断片化が酷かった。なんでこうなるんや…(多分どうやったら後ろ側にファイルを置けるか色々やったんだと思うけど)
断片化したext 10個未満になるように探索した感じ、この辺りが断片化が少ない状態のようでした。あと不思議なことにこっちの方がphysical_offsetが大きいですね。大小、ワークロードも異なることに考慮しながらディスクにデータを書き込むのは大変難しそうですね…(他人事)
$ filefrag -v /mnt/dummy_file.00003234 Filesystem type is: ef53 File size of /mnt/dummy_file.00003234 is 10737418240 (2621440 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 102399: 8786964480..8787066879: 102400: unwritten 1: 102400.. 593919: 8787099648..8787591167: 491520: 8787066880: unwritten 2: 593920.. 1085439: 8787623936..8788115455: 491520: 8787591168: unwritten 3: 1085440.. 1576959: 8788148224..8788639743: 491520: 8788115456: unwritten 4: 1576960.. 2068479: 8788672512..8789164031: 491520: 8788639744: unwritten 5: 2068480.. 2559999: 8789196800..8789688319: 491520: 8789164032: unwritten 6: 2560000.. 2621439: 8789721088..8789782527: 61440: 8789688320: last,unwritten,eof /mnt/dummy_file.00003234: 7 extents found
全体のBlock数は 32.75(TiB) / 4096(byte) = 8,790,585,600 block あります。
さっきやりましたが、上記の 00000000は、このうちの8,814,592 block目ということになります。 8,814,592 / 8,790,585,600 = 0.0010... ですから、先頭から 0.1% の位置といえます。
次に中間ぐらいにある 00001670 をみてみましょう。こちらは 4,413,708,288 block目からあるようです。先頭から50.2%あたりの位置なのでほぼ真ん中という感じですね。
最後に終端で断片が少なかった 00003234 をみてみましょう。こちらは 8,786,964,480block目 からあるようです。99.95%あたりの位置なのでほぼ終端といえるでしょう。
…ただし、RAIDを組んでるのでこのoffsetの先端や終端が実際どこを指しているのかはわかりません。とはいえ多分そんなあちこち分散させるような仕組みにはなってないので、素直にoffset=0はsdaのoffset=0, offset=1はsdbのoffset=0, 見えないパリティ1がsdcのoffset=0, offset=2がsddのoffset=0...というように先頭(おそらく外周)から埋めていく実装になってると思います(ちゃんと実装見なさいと言う話ですがもっと時間がかかってしまいそうで面倒なので…)
まぁ、それを性能結果から観測してみようという話でもあります。
後はそれぞれに対してfioで負荷をかけてみて差がでるかどうかです。
fioで負荷をかけてみる
[global]
bs=512k
buffered=0
direct=1
group_reporting
ioengine=libaio
filename=${FILE_NAME}
norandommap
randrepeat=0
create_serialize=0
size=${FILE_SIZE}
iodepth=${FIO_IODEPTH}
[job]
percentage_random=0
rw=${FIO_RW}
numjobs=1
というbench_fio.fioというファイルを作り、fioで読ませて実行します。環境変数を渡せば変数として置き換えてくれるので便利です。
fioの使い方がよくわからなかったので、スクリプトをかいてiodepthを変えてシーケンシャルリードとライトを計測してログに残すというのをやってます。JSON形式で出力もできるんですが、そのままの出力が人の目で見た時に見やすいので…(そのせいでこの後の集計で苦労するのだけど)
#!/bin/bash # bench_fio.sh /mnt/dummy_file.00003000 set -ue # 変数設定 SCRIPT_HOME=$(cd "$(dirname "$0")" && pwd) . $SCRIPT_HOME/settings.sh export FILE_NAME="$1" export FILE_SIZE LOG_DIR="$SCRIPT_HOME/logs/$(date +%Y%m%d-%H%M%S)-$(basename $FILE_NAME)" mkdir -p "$LOG_DIR" PID_LIST=() function teardown(){ kill "${PID_LIST[@]}" } trap teardown EXIT atop -a 1 -w "$LOG_DIR/atop.log" & PID_LIST+=($!) sleep 3; # お好みで設定 for FIO_IODEPTH in 1 4 8 16; do for FIO_RW in write read; do export FIO_RW FIO_IODEPTH REPORT_DIR="$LOG_DIR/iodepth=$FIO_IODEPTH/rw=$FIO_RW" mkdir -p "$REPORT_DIR" fio "$SCRIPT_HOME/bench_fio.fio" | tee "$REPORT_DIR/fio.log" sleep 3; done done sleep 3;
settings.shはただ変数設定をしているだけです。実際にはソースをご覧ください。また、atopを別途入れて使っています。CPU使用率やディスクの負荷状況などをいい感じにログに残せます。
これをこんな感じで実行します。
sudo bash -x bench_fio.sh /mnt/dummy_file.00000000
一番性能がよかったiodepth=16の時の読み書きを見ましょう。IOPSとbandwidth(bw)は平均です。
offsetはfilefragで確認した大体の位置です。50%からの落ち方が急だったので75%(2505) 90%(3006)あたりも見てみましょう。
| filename | offset(%) | read bw | read iops | write bw | write iops |
|---|---|---|---|---|---|
| 00000000 | 0.0% | 828MiB/s | 1656 | 170MiB/s | 340 |
| 00001670 | 50.2% | 805MiB/s | 1609 | 158MiB/s | 316 |
| 00002505 | 76.7% | 628MiB/s | 1255 | 138MiB/s | 275 |
| 00003006 | 92.7% | 511MiB/s | 1021 | 122MiB/s | 243 |
| 00003234 | 99.9% | 438MiB/s | 875 | 110MiB/s | 219 |
サンプル数は1回だけなのですが、あまりHDDに負担をかけたくないので許してください。。
しかし上記の通り、offset値が大きくなるほど性能が落ちていることが分かります。これはHDD特有の現象といえそうです。つまり内周に向かうほど性能が落ちるということです。(これだけで決めつけるのはあまり良くない気はしますが)
ただ、50%ぐらいまではさほど劣化しないようなので、一種の目安には良いかもしれません。
サンプル数も1回だけなのと10GiBというあまり大きくないサイズでしたが、傾向としては充分だと思います。
断片化が酷いファイルに読み書きするとどうなるか試す
そういえばextentsがやたら多いものは除外していましたが、普通に使い潰していれば起き得るでしょう。
次でファイル毎のextentsが分かります。
ls -U /mnt | xargs -n 100 filefrag -X > check-ext-size.log sort -n -k 2 < check-ext-size.log
こんな感じの結果が得られます。
/mnt/dummy_file.00001569: 8 extents found /mnt/dummy_file.00001568: 9 extents found /mnt/dummy_file.00001571: 35 extents found /mnt/dummy_file.00001663: 49 extents found /mnt/dummy_file.00003235: 67 extents found /mnt/dummy_file.00001574: 92 extents found ... /mnt/dummy_file.00003323: 93 extents found /mnt/dummy_file.00003325: 93 extents found /mnt/dummy_file.00003326: 133 extents found /mnt/dummy_file.00003339: 2288 extents found /mnt/dummy_file.00003327: 2560 extents found
ここを眺めながらextentsが変動しているファイルをピックアップします。
(ちょっと冗長なので折りたたんでおきます)
# 先頭よりだけど結構まばら $ filefrag -v /mnt/dummy_file.00001571 Filesystem type is: ef53 File size of /mnt/dummy_file.00001571 is 10737418240 (2621440 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 282623: 7057408.. 7340031: 282624: 1: 282624.. 774143: 7372800.. 7864319: 491520: 7340032: 2: 774144.. 839679: 7897088.. 7962623: 65536: 7864320: 3: 839680.. 1259519: 7968768.. 8388607: 419840: 7962624: 4: 1259520.. 1652735: 8421376.. 8814591: 393216: 8388608: 5: 1652736.. 1685503: 360448.. 393215: 32768: 8814592: 6: 1685504.. 1744895: 301056.. 360447: 59392: 393216: 7: 1744896.. 1804287: 235520.. 294911: 59392: 360448: 8: 1804288.. 1863679: 169984.. 229375: 59392: 294912: 9: 1863680.. 1923071: 104448.. 163839: 59392: 229376: 10: 1923072.. 1982463: 38912.. 98303: 59392: 163840: 11: 1982464.. 2011135: 3672096.. 3700767: 28672: 98304: 12: 2011136.. 2039807: 3147808.. 3176479: 28672: 3700768: 13: 2039808.. 2068479: 2623520.. 2652191: 28672: 3176480: 14: 2068480.. 2097151: 2099232.. 2127903: 28672: 2652192: 15: 2097152.. 2125823: 1574944.. 1603615: 28672: 2127904: 16: 2125824.. 2154495: 1050656.. 1079327: 28672: 1603616: 17: 2154496.. 2183167: 526368.. 555039: 28672: 1079328: 18: 2183168.. 2199551: 16384.. 32767: 16384: 555040: 19: 2199552.. 2207743: 6290.. 14481: 8192: 32768: 20: 2207744.. 2236415: 7866400.. 7895071: 28672: 14482: 21: 2236416.. 2265087: 7342112.. 7370783: 28672: 7895072: 22: 2265088.. 2293759: 6817824.. 6846495: 28672: 7370784: 23: 2293760.. 2322431: 6293536.. 6322207: 28672: 6846496: 24: 2322432.. 2351103: 5769248.. 5797919: 28672: 6322208: 25: 2351104.. 2379775: 5244960.. 5273631: 28672: 5797920: 26: 2379776.. 2408447: 4720672.. 4749343: 28672: 5273632: 27: 2408448.. 2437119: 4196384.. 4225055: 28672: 4749344: 28: 2437120.. 2465791: 12060704.. 12089375: 28672: 4225056: 29: 2465792.. 2494463: 11536416.. 11565087: 28672: 12089376: 30: 2494464.. 2523135: 11012128.. 11040799: 28672: 11565088: 31: 2523136.. 2551807: 10487840.. 10516511: 28672: 11040800: 32: 2551808.. 2580479: 9963552.. 9992223: 28672: 10516512: 33: 2580480.. 2609151: 9439264.. 9467935: 28672: 9992224: 34: 2609152.. 2621439: 8914976.. 8927263: 12288: 9467936: last,eof /mnt/dummy_file.00001571: 35 extents found # 中間あたりでまとまっているが断片化 $ filefrag -v /mnt/dummy_file.00001663 Filesystem type is: ef53 File size of /mnt/dummy_file.00001663 is 10737418240 (2621440 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 8191: 4373635072..4373643263: 8192: unwritten 1: 8192.. 16383: 4373624864..4373633055: 8192: 4373643264: unwritten 2: 16384.. 45055: 4374136864..4374165535: 28672: 4373633056: unwritten (中略) 47: 1910784.. 2402303: 4396187648..4396679167: 491520: 4396154880: unwritten 48: 2402304.. 2621439: 4396711936..4396931071: 219136: 4396679168: last,unwritten,eof /mnt/dummy_file.00001663: 49 extents found # 大半は中間あたりでまとまっているが断片化 $ filefrag -v /mnt/dummy_file.00003235 Filesystem type is: ef53 File size of /mnt/dummy_file.00003235 is 10737418240 (2621440 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 430079: 8789782528..8790212607: 430080: unwritten 1: 430080.. 770047: 8790245376..8790585343: 339968: 8790212608: unwritten 2: 770048.. 798719: 4395632672..4395661343: 28672: 8790585344: unwritten (中略) 42: 1163264.. 1165311: 4395134976..4395137023: 2048: 4394612768: unwritten 43: 1165312.. 1169407: 4395130880..4395134975: 4096: 4395137024: unwritten 44: 1169408.. 1189887: 4395108384..4395128863: 20480: 4395134976: unwritten 45: 1189888.. 1419263: 4395401216..4395630591: 229376: 4395128864: unwritten 46: 1419264.. 1910783: 4395663360..4396154879: 491520: 4395630592: unwritten 47: 1910784.. 2402303: 4396187648..4396679167: 491520: 4396154880: unwritten /mnt/dummy_file.00003235: 67 extents found # 激しく断片化 $ filefrag -v /mnt/dummy_file.00003326 Filesystem type is: ef53 File size of /mnt/dummy_file.00003326 is 10737418240 (2621440 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 16383: 8743567360..8743583743: 16384: unwritten 1: 16384.. 24575: 8743557152..8743565343: 8192: 8743583744: unwritten 2: 24576.. 53247: 8744077344..8744106015: 28672: 8743565344: unwritten 3: 53248.. 81919: 8744601632..8744630303: 28672: 8744106016: unwritten (中略) 89: 2519040.. 2547711: 8789690400..8789719071: 28672: 8789194784: unwritten 90: 2547712.. 2578431: 8790214168..8790244887: 30720: 8789719072: unwritten 91: 2578432.. 2580478: 4395137024..4395139070: 2047: 8790244888: unwritten 92: 2580479.. 2580479: 4395128864..4395128864: 1: 4395139071: unwritten 93: 2580480.. 2582495: 4395661344..4395663359: 2016: 4395128865: unwritten 94: 2582496.. 2582527: 8790585344..8790585375: 32: 4395663360: unwritten 95: 2582528.. 2584543: 555040.. 557055: 2016: 8790585376: unwritten 96: 2584544.. 2584575: 8790585376..8790585407: 32: 557056: unwritten 97: 2584576.. 2586591: 1079328.. 1081343: 2016: 8790585408: unwritten 98: 2586592.. 2586623: 8790585408..8790585439: 32: 1081344: unwritten 99: 2586624.. 2588639: 1603616.. 1605631: 2016: 8790585440: unwritten 100: 2588640.. 2588671: 1609856.. 1609887: 32: 1605632: unwritten 101: 2588672.. 2590687: 2127904.. 2129919: 2016: 1609888: unwritten 102: 2590688.. 2590719: 8790585440..8790585471: 32: 2129920: unwritten 103: 2590720.. 2592735: 2652192.. 2654207: 2016: 8790585472: unwritten 104: 2592736.. 2592767: 2658432.. 2658463: 32: 2654208: unwritten 105: 2592768.. 2594783: 3176480.. 3178495: 2016: 2658464: unwritten 106: 2594784.. 2594815: 8790585472..8790585503: 32: 3178496: unwritten 107: 2594816.. 2596831: 3700768.. 3702783: 2016: 8790585504: unwritten 108: 2596832.. 2596863: 8790585504..8790585535: 32: 3702784: unwritten 109: 2596864.. 2598879: 4225056.. 4227071: 2016: 8790585536: unwritten 110: 2598880.. 2598911: 8790585536..8790585567: 32: 4227072: unwritten 111: 2598912.. 2600927: 4749344.. 4751359: 2016: 8790585568: unwritten 112: 2600928.. 2600959: 8790585568..8790585599: 32: 4751360: unwritten 113: 2600960.. 2602975: 5273632.. 5275647: 2016: 8790585600: unwritten 114: 2602976.. 2603007: 103904.. 103935: 32: 5275648: unwritten 115: 2603008.. 2605023: 5797920.. 5799935: 2016: 103936: unwritten 116: 2605024.. 2605055: 103936.. 103967: 32: 5799936: unwritten 117: 2605056.. 2607071: 6322208.. 6324223: 2016: 103968: unwritten 118: 2607072.. 2607103: 103968.. 103999: 32: 6324224: unwritten 119: 2607104.. 2609119: 6846496.. 6848511: 2016: 104000: unwritten 120: 2609120.. 2609151: 104000.. 104031: 32: 6848512: unwritten 121: 2609152.. 2611167: 7370784.. 7372799: 2016: 104032: unwritten 122: 2611168.. 2611199: 104032.. 104063: 32: 7372800: unwritten 123: 2611200.. 2613215: 7895072.. 7897087: 2016: 104064: unwritten 124: 2613216.. 2613247: 7966848.. 7966879: 32: 7897088: unwritten 125: 2613248.. 2615263: 8419360.. 8421375: 2016: 7966880: unwritten 126: 2615264.. 2615295: 104064.. 104095: 32: 8421376: unwritten 127: 2615296.. 2617311: 8935456.. 8937471: 2016: 104096: unwritten 128: 2617312.. 2617343: 104096.. 104127: 32: 8937472: unwritten 129: 2617344.. 2619359: 9467936.. 9469951: 2016: 104128: unwritten 130: 2619360.. 2619391: 104128.. 104159: 32: 9469952: unwritten 131: 2619392.. 2621407: 9992224.. 9994239: 2016: 104160: unwritten 132: 2621408.. 2621439: 104160.. 104191: 32: 9994240: last,unwritten,eof /mnt/dummy_file.00003326: 133 extents found # 終端側だが酷い断片化が起きている $ filefrag -v /mnt/dummy_file.00003339 | head Filesystem type is: ef53 File size of /mnt/dummy_file.00003339 is 9600471040 (2343865 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 2015: 8180496416..8180498431: 2016: unwritten 1: 2016.. 2047: 8152186592..8152186623: 32: 8180498432: unwritten 2: 2048.. 4063: 8181020704..8181022719: 2016: 8152186624: unwritten 3: 4064.. 4095: 8152186624..8152186655: 32: 8181022720: unwritten 4: 4096.. 6111: 8181544992..8181547007: 2016: 8152186656: unwritten 5: 6112.. 6143: 8152186656..8152186687: 32: 8181547008: unwritten 6: 6144.. 8159: 8182069280..8182071295: 2016: 8152186688: unwritten $ filefrag -v /mnt/dummy_file.00003339 | tail 2279: 2334688.. 2334719: 8786573408..8786573439: 32: 8787623936: unwritten 2280: 2334720.. 2336735: 8788146208..8788148223: 2016: 8786573440: unwritten 2281: 2336736.. 2336767: 8786573440..8786573471: 32: 8788148224: unwritten 2282: 2336768.. 2338783: 8788670496..8788672511: 2016: 8786573472: unwritten 2283: 2338784.. 2338815: 8786573472..8786573503: 32: 8788672512: unwritten 2284: 2338816.. 2340831: 8789194784..8789196799: 2016: 8786573504: unwritten 2285: 2340832.. 2340863: 8786573504..8786573535: 32: 8789196800: unwritten 2286: 2340864.. 2342879: 8789719072..8789721087: 2016: 8786573536: unwritten 2287: 2342880.. 2343864: 8786573536..8786574520: 985: 8789721088: last,unwritten,eof
ということで、少し断片化が進んだファイルたちにベンチマークをかけたらどうなるか見てみましょう。
新しくいくつかのファイルに対してfioの結果をくっつけたのが以下。iodepthはやはり16が一番よかったのでその結果で見ています。
大体はoffset順ですが、offsetは上記の通りばらばらのファイルもあったのでそこは"-"にしています。
| filename | extents | offset(%) | read | read iops | write | write iops |
|---|---|---|---|---|---|---|
| 00000000 | 8 | 0.0% | 828.0 MiB/s | 1656 | 170.0 MiB/s | 340 |
| 00001571 | 35 | - | 835.0 MiB/s | 1669 | 164.0 MiB/s | 328 |
| 00001663 | 53 | 49.7% | 750.0 MiB/s | 1499 | 147.0 MiB/s | 293 |
| 00003235 | 71 | 50.0% | 602.0 MiB/s | 1203 | 129.0 MiB/s | 258 |
| 00001670 | 6 | 50.2% | 805.0 MiB/s | 1609 | 158.0 MiB/s | 316 |
| 00002505 | 7 | 76.7% | 628.0 MiB/s | 1255 | 138.0 MiB/s | 275 |
| 00001574 | 96 | - | 807.0 MiB/s | 1613 | 146.0 MiB/s | 291 |
| 00003326 | 137 | - | 396.0 MiB/s | 792 | 93.7 MiB/s | 187 |
| 00003006 | 7 | 92.7% | 511.0 MiB/s | 1021 | 122.0 MiB/s | 243 |
| 00003339 | 2292 | 93.0% | 257.0 MiB/s | 513 | 44.2 MiB/s | 88 |
| 00003234 | 7 | 99.9% | 438.0 MiB/s | 875 | 110.0 MiB/s | 219 |
こうしてみると、以下の傾向が見えます。
- offset値が大きいほど性能が低下する(00000000 と 00003234 が顕著)
- extentsが多いほど若干性能が落ちる(00003235 と 00001670 がほぼ同じoffset位置だが結果に差が出ている)
繰り返しになりますが、今回はmdadmでRAID6を組んでるので、そのまま使った場合と比べると差はあるかもしれません。また10GiB1ファイルのベンチマークなんて、実際のユースケースに当てはまらないのであまりアテになりません。 SSDが普及した今、HDDに性能を求めるのは荷が重すぎるってもんです。有利なのは容量あたりの値段ぐらいです。
なのでこの結果は「そんなこともあるんだ」ぐらいに捉え、実際は自分のユースケースに当てはめてベンチマークを取るのが良いでしょう。
今回使ったコードとかログは以下に置いておきます。
おわり
なんでこんなことしているのかといえば「次のNASのファイルシステムどうしようか」という一環で調べているというところはあります。本当は簡単なシーケンシャルな読み書きだけ試そうとしていたのですが、ちょっと気になってしまい大いに脱線しましたが。
今回はext4(on mdamd RAID-6)でしたが、せっかくなのでXFS (on mdadm RAID-6), Btrfs (on mdadm RAID-6), OpenZFS (RAID-Z2) あたりでもやってみたい感はあります。(やるとはいっていない)
LVMは…まぁ…うん。