RAID6上に構成したext4ファイルシステムのベンチマークを取る際にオフセットや断片化に配慮してとってみた

今さらHDDのRAIDベンチマークやってます。

背景

  • HDD * 8でRAID-6を組んで32TiBになったディスクアレイ上に構成したファイルシステムにfioでベンチマークをしたい
  • HDD単体の外周内周?については過去にやっているし、RAID6に対しても構築時にやったので、新規性が欲しいと考えた
    • ストレージ系のベンチマークは全く使っていない状態に対して行うことがほとんどなので、空きがある状態(効率的に扱える状態)であったり、断片化が起きてない状態で実施するので、そうでない場合の性能も見たい
    • RAID6でも物理的に効率的に使えない状態での性能をちょっと見てみたかった
  • そのためにはまず内周と外周にファイルを置く必要がある
    • fio自体にoffsetはあるが、これはdevice限定らしくファイルシステムを無視してデバイスを直接読み書きするので実際の用途とは異なる
  • やっていて気付いたが、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に性能を求めるのは荷が重すぎるってもんです。有利なのは容量あたりの値段ぐらいです。

なのでこの結果は「そんなこともあるんだ」ぐらいに捉え、実際は自分のユースケースに当てはめてベンチマークを取るのが良いでしょう。

今回使ったコードとかログは以下に置いておきます。

github.com

おわり

なんでこんなことしているのかといえば「次のNASファイルシステムどうしようか」という一環で調べているというところはあります。本当は簡単なシーケンシャルな読み書きだけ試そうとしていたのですが、ちょっと気になってしまい大いに脱線しましたが。

今回はext4(on mdamd RAID-6)でしたが、せっかくなのでXFS (on mdadm RAID-6), Btrfs (on mdadm RAID-6), OpenZFS (RAID-Z2) あたりでもやってみたい感はあります。(やるとはいっていない)

LVMは…まぁ…うん。