Ubuntu Weekly Recipe

第749回LXDとUbuntuサーバーで、多数のストレージが必要なRAID環境を構築し性能を比較する

第748回のLXDとUbuntuサーバーでRAIDとmdadmのテスト環境を構築するでは、LXDを使ってかんたんに単一のマシンにRAID 1環境を構築する方法を紹介しました。今回は前回紹介しきれなかった残りのRAIDレベルを構築し、それぞれの性能を比較してみましょう。

さまざまなRAIDレベルたち

RAIDにはいくつかのレベルとそれを組み合わせたものが存在します[1]。そのうちUbuntuがインストーラーとしてサポートしているのは、RAID 0、1、5、6、10の5種類です。もちろんインストーラーはUbuntuのルートファイルシステムを構築するための仕組みなので、純粋なデータ領域をRAIDとして構築するのであれば、mdadmコマンドを用いてさらに複雑な構成が可能になります。

まずは第748回の手順に従って、RAID 1、5、6、10について紹介しましょう。やっていることは第748回をベースにしています。環境の構築方法は第748回の「LXDに専用ストレージプールを作成する」を参照してください。使っているコマンドについては「RAID 1:2台から始められるミラーリングシステム」で解説しています。今回はオプションはほぼそのままで、ストレージの台数だけを増やした形になりますので、lxcコマンドのオプションについて気になるようであれば、第748回も参照してください。

RAID 5:速度と冗長性と利用効率のバランス重視=虻蜂取らず

UbuntuのインストーラーはRAID 2、3および4には対応していません。使用効率が悪い、計算量が多い、I/O性能が出ないなどその理由はいろいろあるものの、ソフトウェアRAIDとしては使う利点が少ないというのが結論となります。

これらの欠点をある程度解消したのがRAID 5です。RAID 0のようにデータを複数のストレージに分散して記録しつつ、データのパリティを計算し、これも分散して記録する方式です。最低3台のストレージが必要ではあるものの、1台分の容量のみをパリティとして使うだけで、ストレージの利用効率にも優れています。RAID 0の速度とRAID 1の冗長性を兼ね備えた良いとこ取りという触れ書きですが、1台壊れるだけで速度も信頼性も大きく低下します。よってソフトウェアRAIDにおいてRAID 5を使うのは限定的なケースと思っておけば良いでしょう。

RAID 5は最低3台なので3台構成で構築してみましょう。インスタンス名はraid5⁠、カスタムストレージボリュームはraid5braid5cとします。

$ lxc init raid5 --empty --vm -c limits.cpu=2 -c limits.memory=8GiB --storage raid
$ lxc config device set raid5 root size=40GiB
$ lxc config device add raid5 iso disk boot.priority=1 source=$HOME/ダウンロード/ubuntu-22.04.1-live-server-amd64.iso
$ lxc storage volume create raid raid5b --type=block size=40GiB
$ lxc storage volume create raid raid5c --type=block size=40GiB
$ lxc storage volume attach raid raid5b raid5
$ lxc storage volume attach raid raid5c raid5
$ lxc start raid5 --console=vga

ストレージの設定は次のようになります。最低ひとつのESP(EFI System Partition)が必要であること、3台の空の(Formatを「Leave unforamtted」にしている)パーティションを作ること、用意できたら「Create software RAID (md)」を選択する部分は、第748回と同じです。

図1 3台のストレージが認識されていることを確認する
図1
図2 RAID 5なので3台のパーティションを「active」にしておく
図2
図3 作成したmd0は約39GiBが3台で117GiBのところ、RAID 5の場合は2台分の約78GiBしか使えない形になる
図3

インストール後再起動して、状態を確認すると次のような結果になります。

$ cat /proc/mdstat
Personalities : [raid6] [raid5] [raid4] [linear] [multipath] [raid0] [raid1] [raid10]
md0 : active raid5 sdc2[1] sdb2[0] sda2[3]
      81612800 blocks super 1.2 level 5, 512k chunk, algorithm 2 [3/3] [UUU]

unused devices: <none>

$ sudo mdadm --detail /dev/md0
/dev/md0:
           Version : 1.2
     Creation Time : Sun Jan 29 11:59:59 2023
        Raid Level : raid5
        Array Size : 81612800 (77.83 GiB 83.57 GB)
     Used Dev Size : 40806400 (38.92 GiB 41.79 GB)
      Raid Devices : 3
     Total Devices : 3
       Persistence : Superblock is persistent

       Update Time : Sun Jan 29 13:00:55 2023
             State : clean
    Active Devices : 3
   Working Devices : 3
    Failed Devices : 0
     Spare Devices : 0

            Layout : left-symmetric
        Chunk Size : 512K

Consistency Policy : resync

              Name : ubuntu-server:0
              UUID : d7b8174e:a3f77ba5:4b85fb03:8f1d951f
            Events : 252

    Number   Major   Minor   RaidDevice State
       0       8       18        0      active sync   /dev/sdb2
       1       8       34        1      active sync   /dev/sdc2
       3       8        2        2      active sync   /dev/sda2

RAID 1のときと比べると、台数やサイズ等の違いに加えて、次のようなフィールドが追加されています。

            Layout : left-symmetric
        Chunk Size : 512K

Layoutはデータとパリティを、どの順番でストレージに書き込んでいくかを表しています。Chunk Sizeは、あるデータを書き込む際に、複数のストレージに分割して書き込む際の単位です。上記の例だと512KiBごとに分割されて書き込まれることになります。この値は性能にも影響してくるのですが、用途等に応じて最適値は変わってくるので注意してください。

RAID 5の場合、パリティ用の領域は1台分となります。そのため台数が増えるほど、ストレージの利用効率はあがります。たとえばnTBが3台なら2nTB(67%⁠⁠、4台なら3nTB(75%)といった具合に増えていくのです。ただし台数が増えてくるほど、故障に遭遇する確率はあがります。RAID 5の場合、同時に故障を許容できるのは1台までです。つまり1台故障して、ストレージを交換して、再構築を行っている間にもう1台壊れてしまうとその時点で復旧不能となります。

さらに最近の大きな容量のHDDだと、再構築時の読み込みエラー数も無視できません。結果的にRAID 5は、RAIDとして扱いづらい位置づけになりました。

RAID 6:2台壊れてもなんとかなる堅牢性

RAID 6はRAID 5をベースに、パリティを複数のストレージに書き込む方式です。このため最低台数は4台からとなりますが、2台壊れてもなんとかなる(と期待できる)堅牢性を確保しています。ただしパリティの計算量は増えますので、ソフトウェアRAIDだと若干不利な構成です。台数が多めのRAIDを構築する際に、ストレージの利用効率をあげたい場合の選択肢になってくるでしょう。

RAID 6もとりあえず最低必要台数の4台で構築してみます。インスタンス名はraid6⁠、カスタムストレージボリュームはraid6braid6craid6dとします。

$ lxc init raid6 --empty --vm -c limits.cpu=2 -c limits.memory=8GiB --storage raid
$ lxc config device set raid6 root size=40GiB
$ lxc config device add raid6 iso disk boot.priority=1 source=$HOME/ダウンロード/ubuntu-22.04.1-live-server-amd64.iso
$ lxc storage volume create raid raid6b --type=block size=40GiB
$ lxc storage volume create raid raid6c --type=block size=40GiB
$ lxc storage volume create raid raid6d --type=block size=40GiB
$ lxc storage volume attach raid raid6b raid6
$ lxc storage volume attach raid raid6c raid6
$ lxc storage volume attach raid raid6d raid6
$ lxc start raid6 --console=vga

インストール手順も同じなので、最終的な構成結果だけ残しておきます。

図4 作成したmd0は約39GiBが3台で156GiBのところ、RAID 6の場合も2台分の約78GiBしか使えない形になる
図4
$ cat /proc/mdstat
Personalities : [raid6] [raid5] [raid4] [linear] [multipath] [raid0] [raid1] [raid10]
md0 : active raid6 sdc2[1] sdb2[0] sda2[3] sdd2[2]
      81612800 blocks super 1.2 level 6, 512k chunk, algorithm 2 [4/4] [UUUU]

unused devices: <none>

$ sudo mdadm --detail /dev/md0
/dev/md0:
           Version : 1.2
     Creation Time : Sun Jan 29 14:54:09 2023
        Raid Level : raid6
        Array Size : 81612800 (77.83 GiB 83.57 GB)
     Used Dev Size : 40806400 (38.92 GiB 41.79 GB)
      Raid Devices : 4
     Total Devices : 4
       Persistence : Superblock is persistent

       Update Time : Sun Jan 29 15:02:01 2023
             State : clean
    Active Devices : 4
   Working Devices : 4
    Failed Devices : 0
     Spare Devices : 0

            Layout : left-symmetric
        Chunk Size : 512K

Consistency Policy : resync

              Name : ubuntu-server:0
              UUID : 73ab874d:5cd3dd66:9e3aa7c6:235a4ca1
            Events : 187

    Number   Major   Minor   RaidDevice State
       0       8       18        0      active sync   /dev/sdb2
       1       8       34        1      active sync   /dev/sdc2
       2       8       50        2      active sync   /dev/sdd2
       3       8        2        3      active sync   /dev/sda2

RAID 6は台数を増やして容量を稼ぎたい場合の選択肢になってくるでしょう。ただし、再構築時に故障が起きやすい弱点についてはRAID 5と同じです。2台壊れるよりも3台壊れることのほうが少ないだろうという期待を込めて「RAID 6のほうがまし」となっています。

RAID 10:RAID 0と1のいいとこどりでCPUに優しい構成

ここまで紹介したRAIDはいずれも単体のRAIDレベルで構成されていました。それに対して「Nested RAID」は複数のRAIDレベルを組み合わせる方式です。

たとえば「RAID 1+0」は、RAID 1構成の2台のストレージを2セット用意し、それをRAID 0として分散する方式です。これにより、RAID 1の堅牢性とRAID 0の高速化の良いとこ取りができます。理論上はさまざまなRAIDレベルを組み合わせることが可能で、たとえばRAID 6を多重化することで最大8台壊れても大丈夫にする「RAID 6+6」なども考えられます。これらは「RAID 10」「RAID 66」などと表記されることもあります。

一般的にNested RAIDはその分だけ必要なストレージの台数が増えます。RAID 6+6になると最低16台のストレージが必要ですし、RAID 1+0でも4台必要です。構成も複雑になりがちですが、その分それぞれのレベルの利点を組み合わせやすくなります。

さて、Ubuntuのインストーラーは「RAID 10」をサポートしています[2]。これは前述の「RAID 1+0」に近いものですが、正確には異なるものなので注意が必要です。一般的なRAID 1+0はRAID 1でミラーリングしている2台を2セット用意して、RAID 0で分散することで高速化を試みます。つまりRAIDレベルとして明確に2種類のレイヤーとしてわかれています。そのため最低でも4台のストレージが必要です。それに対してLinux MDのRAID 10は単一のレイヤーで同等の機能を実現します。その際、データをどのように配置するかによって実際の機能が異なってきますし、最低2台でも構成が可能です[3]

RAID 10で使用できる具体的なデータレイアウトについては、md(4)のmanページのRAID 10の項目英語版のWikipediaの項目Il sistemistaの説明などが参考になります。かんたんに説明すると、あるデータブロック(chunk)の複製(レプリカ)をいくつ作り、どこに記録するかによって次の3パターンが存在します。

  • near:複製chunkを元のchunkを書き込んだストレージから、複製先のストレージ上のできるだけ近い位置に書き込む
  • far:複製chunkを元のchunkを書き込んだストレージから、複製先のストレージ上の十分に遠い位置に書き込む
  • offset:複製chunkを元のchunkを書き込んだストレージに対して、距離を指定した値の分だけずらしたストレージに書き込む

nearレイアウトで、複製を1個作成する(レプリカ数が2になる)場合は「near2」と表記します。4台構成のnear2はRAID 1+0そのもので、2台構成のnear2はRAID 1そのものです。性能や耐障害性についてはそれらの仕組みに準じます。

farレイアウトは個々のストレージをオリジナルのデータを記録する領域と、複製chunkを記録する領域に分割した上で、同じストレージにオリジナルと複製データの両方が書き込まれてしまわないように調整しています。オリジナルのデータが個々のストレージデバイスの近い領域にまとまっていることで、理論上はシーケンシャル読み込みの性能が向上しますが、書き込み性能は落ちます。実際のところは、ワークロードによってnear/far/offsetのどれが適しているのかが変わってきます。

RAID 10は複製を1個作成するのであれば、1台までの故障であれば復旧可能です。また、連続しない2台の故障でも復旧できる可能性があります。よってRAID 6よりは耐障害性が若干低くなるのですが、パリティ計算をしなくて良い分、CPUに優しい構成となります。ただしパリティの代わりにデータを複製する以上、利用可能な容量はRAID 1と同様に半分以下となってしまいます。

さらにRAID 10の特徴としてレプリカ数を指定できる点にあります。当然のことながらそのぶんストレージの利用効率は落ちるわけですが、その分耐障害性があがります。また異なるレイアウトを組み合わせて使うことも可能です。

説明が長くなってしまいましたが、4台構成でRAID 10を構築してみしょう。インスタンス名はraid10⁠、カスタムストレージボリュームはraid10braid10craid10dとします。

$ lxc init raid10 --empty --vm -c limits.cpu=2 -c limits.memory=8GiB --storage raid
$ lxc config device set raid10 root size=40GiB
$ lxc config device add raid10 iso disk boot.priority=1 source=$HOME/ダウンロード/ubuntu-22.04.1-live-server-amd64.iso
$ lxc storage volume create raid raid10b --type=block size=40GiB
$ lxc storage volume create raid raid10c --type=block size=40GiB
$ lxc storage volume create raid raid10d --type=block size=40GiB
$ lxc storage volume attach raid raid10b raid10
$ lxc storage volume attach raid raid10c raid10
$ lxc storage volume attach raid raid10d raid10
$ lxc start raid10 --console=vga

インストール手順も同じなので、最終的な構成結果だけ残しておきます。

図5 残念ながらレイアウトは選べず、常にnear2となる
図5
$ cat /proc/mdstat
Personalities : [raid10] [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4]
md0 : active raid10 sdc2[1] sdb2[0] sdd2[2] sda2[3]
      81612800 blocks super 1.2 512K chunks 2 near-copies [4/4] [UUUU]

unused devices: <none>

$ sudo mdadm --detail /dev/md0
/dev/md0:
           Version : 1.2
     Creation Time : Sat Feb  4 10:33:34 2023
        Raid Level : raid10
        Array Size : 81612800 (77.83 GiB 83.57 GB)
     Used Dev Size : 40806400 (38.92 GiB 41.79 GB)
      Raid Devices : 4
     Total Devices : 4
       Persistence : Superblock is persistent

       Update Time : Sat Feb  4 10:48:36 2023
             State : active
    Active Devices : 4
   Working Devices : 4
    Failed Devices : 0
     Spare Devices : 0

            Layout : near=2
        Chunk Size : 512K

Consistency Policy : resync

              Name : ubuntu-server:0
              UUID : ce802cc9:9563225b:8afe8fca:f22cf8d3
            Events : 302

    Number   Major   Minor   RaidDevice State
       0       8       18        0      active sync set-A   /dev/sdb2
       1       8       34        1      active sync set-B   /dev/sdc2
       2       8       50        2      active sync set-A   /dev/sdd2
       3       8        2        3      active sync set-B   /dev/sda2

上記の「Layout」を見るとわかるように「near=2」とnear2レイアウトとなっています。

            Layout : near=2

残念ながらUbuntuのインストーラーでは、near2以外のRAID10は選択できません。

性能テスト

UbuntuがサポートしているRAIDレベルを一通りセットアップできたところで、それぞれの速度を確認してみましょう。ちなみUbuntuをインストールした状態のRAID 1(2台⁠⁠、RAID 5(3台⁠⁠、RAID 6(4台⁠⁠、RAID 10(4台)を合わせたストレージの利用料は次のようになりました。

$ lxc storage info raid
info:
  description: ""
  driver: btrfs
  name: raid
  space used: 115.06GiB
  total space: 372.53GiB

では、それぞれ速度にどれくらいの違いがでるのか、簡易的に確認してみましょう。Ubuntuにおけるストレージの速度計測だと、fioが定番です。パッケージから簡単にインストールできるのでインストールしてしまいましょう。今回はJSONで出力したものをパースしたいので、jqも合わせてインストールしておきます。

$ sudo apt install fio jq

fioはあまりにも設定パラメーターが多く、実際に計測する際にどれをどう選べば良いか判断が難しいところです。言い方をかえると、このあたりのパラメーターをきちんと理解できる人でないと正しい計測はできないということでもあるのですが、そこはそれ。精度や想定しているワークロードとかは置いておいてともかくカジュアルに測りたい場合には不便です。というわけで、それっぽいパラメーターをでっちあげてみました。これを設定ファイルとして流用することにしましょう。

$ cat <<EOF > cdm.fio
[global]
ioengine=libaio
iodepth=1
size=1g
direct=1
loops=5
runtime=30
filename=cdm
directory=/tmp/
stonewall

[SEQ1MQ8T1-Read]
bs=1m
iodepth=8
numjobs=1
rw=read

[SEQ1MQ8T1-Write]
bs=1m
iodepth=8
numjobs=1
rw=write

[SEQ128KQ32T1-Read]
bs=128k
iodepth=32
group_reporting
numjobs=1
rw=read

[SEQ128KQ32T1-Write]
bs=128k
iodepth=32
numjobs=1
rw=write

[RND4KQ32T16-Read]
bs=4k
iodepth=32
numjobs=16
group_reporting
rw=randread

[RND4KQ32T16-Write]
bs=4k
iodepth=32
numjobs=16
group_reporting
rw=randwrite

[RND4KQ1T11-Read]
bs=4k
iodepth=1
numjobs=1
rw=randread

[RND4KQ1T1-Write]
bs=4k
iodepth=1
numjobs=1
rw=randwrite
EOF

個々の設定項目の詳細についてはfioのドキュメントを参照してください。

これを実機で動かすためには次のように実行します。

$ fio -f cdm.fio --output-format=json --output=results.json

これでresults.jsonが得られたわけですが、このままだとどの値を見ればよいかがよくわかりません。そこで代表的な値だけを抜き出して整形してみましょう。

$ jq -r '.jobs[] | [.jobname, if .read.bw > 0 then .read.bw/1000, .read.iops | round
    else .write.bw/1000, .write.iops | round end] | @tsv' \
    results.json | column -t --table-columns JOB,MB/s,IOPS --table-right MB/s,IOPS
JOB                 MB/s    IOPS
SEQ1MQ8T1-Read      3093    3021
SEQ1MQ8T1-Write     2497    2438
SEQ128KQ32T1-Read   3216   25129
SEQ128KQ32T1-Write  2436   19033
RND4KQ32T16-Read    1705  426291
RND4KQ32T16-Write    679  169671
RND4KQ1T11-Read       37    9336
RND4KQ1T1-Write      247   61768

ちなみにデータは/tmp/に作られます。必要に応じて次のように削除しておきましょう。

$ rm /tmp/cdm

これを元に、それぞれのRAIDレベルの結果を調べてみます。ちなみに実際に実行した環境は次のようなマシンです。

機能 メーカー 型番 備考
CPU Intel Core i9-12900 16C/24T 65W
CPUクーラー Noctua NH-L9i-17xx 空冷
メモリー Crucial CT2K32G4DFD832A DDR4-3200 32GBx2
M/B ASRock B660-ITX ITX
ストレージ Crucial P5 Plus 1TB PCIe 4.0x4
GPU Intel UHD Graphics 770 iGPU

ちなみにこのマザーボードはPCIe 4.0x4のM.2 NVMeのスロットがもう一個あります。残念ながらそちらはまだ空っぽで、接続するべきデバイスを絶賛募集中です。

RAIDなし

比較対象のために、ストレージが1台で単なるext4を使っているインスタンスも用意しておきましょう。

JOB                  MB/s    IOPS
SEQ1MQ8T1-Read      20888   20398
SEQ1MQ8T1-Write      5871    5733
SEQ128KQ32T1-Read   23617  184505
SEQ128KQ32T1-Write   6497   50756
RND4KQ32T16-Read     1249  312312
RND4KQ32T16-Write     583  145832
RND4KQ1T11-Read       158   39405
RND4KQ1T1-Write       124   31083

RAID 1

RAID 1は一般的に読み込みは2台並列に行えるので理論上ははやくなるのですが、実際のところは1台からしか読まないことも多く、そこまで良くはならないようです。それに対して書き込みは、両方に書かなければならない都合上、同程度か遅くなってしまいます。

書き込み結果も少し遅くなってしまうようです。

JOB                  MB/s    IOPS
SEQ1MQ8T1-Read      22599   22069
SEQ1MQ8T1-Write      4923    4808
SEQ128KQ32T1-Read   19065  148945
SEQ128KQ32T1-Write   4524   35341
RND4KQ32T16-Read     1164  290932
RND4KQ32T16-Write     345   86349
RND4KQ1T11-Read       153   38184
RND4KQ1T1-Write       116   28916

RAID 5

RAID 5は接続する台数分並列に読み書きできるので、理論的には台数が増えるほど高速になります。しかしながら今回は1個のストレージを仮想的に複数に見せているだけなので、その恩恵にはあずかれません。逆にパリティ計算が必要になった分だけソフトウェアRAIDの場合は遅くなるようです。

JOB                  MB/s    IOPS
SEQ1MQ8T1-Read      21313   20813
SEQ1MQ8T1-Write      2986    2916
SEQ128KQ32T1-Read   15697  122635
SEQ128KQ32T1-Write   3185   24885
RND4KQ32T16-Read     1201  300211
RND4KQ32T16-Write     214   53501
RND4KQ1T11-Read       154   38455
RND4KQ1T1-Write        59   14625

RAID 6

RAID 6もRAID 5と同様に理論的には台数が増えるほど高速になります。ただしソフトウェアRAIDな上に、今回の構成だとその高速化にはあずかれない点も同様です。むしろパリティの書き込みが増えている分、書き込みはRAID 5よりもさらに遅くなります。

JOB                  MB/s    IOPS
SEQ1MQ8T1-Read      21141   20645
SEQ1MQ8T1-Write      2544    2484
SEQ128KQ32T1-Read   13725  107225
SEQ128KQ32T1-Write   2114   16516
RND4KQ32T16-Read     1072  267993
RND4KQ32T16-Write     171   42741
RND4KQ1T11-Read       151   37803
RND4KQ1T1-Write        57   14242

RAID 10 (near2)

RAID 10のnear2については、読み込み程度はRAID 1と同程度、書き込みは台数が増えるほど高速になるもののRAID 0の半分程度というのが理論値です。

RAID 5や6に比べるとパリティ計算がない分だけ、書き込みの性能が向上しています。

JOB                  MB/s    IOPS
SEQ1MQ8T1-Read      19065   18618
SEQ1MQ8T1-Write      7468    7293
SEQ128KQ32T1-Read   16435  128401
SEQ128KQ32T1-Write   5607   43807
RND4KQ32T16-Read     1121  280154
RND4KQ32T16-Write     362   90621
RND4KQ1T11-Read       153   38202
RND4KQ1T1-Write       118   29425

まとめ

当然の結果ではありますが、単一のデバイスを仮想的に分割している以上、RAIDの高速化の恩恵は受けられません。RAID使わないほうがはやいという悲しい結果になりました。

とは言え、高速化は今回の目的ではありません。あくまで、RAID系の操作の習熟が目的です。まずはRAIDを使ったからといって極端に遅くなっているわけではないということだけわかれば十分でしょう。

次回はようやく、RAIDの鬼門であるリビルドにチャレンジしてみます。

おすすめ記事

記事・ニュース一覧