エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

新ストレージ管理システム Stratis について調べてみた

この記事は エムスリー Advent Calendar 2018 17日目の記事です。

皆さんはじめまして!11月にエンジニアリンググループに入りました、SREの平岡です。今回はSRE・・・というよりインフラ技術に携わるエンジニアとして、OSプラットフォーム周辺での新しい技術について紹介します。

8 が・・・来る!

今年(2018年)11月の頭に Red Hat Enterprise Linux (RHEL) 8 のパブリックベータが公開されました。そのリリースノートに挙げられている機能の一つに、新しいストレージ管理システム Stratis があります。

Stratis Storage

多くがまだ未定であろうRHEL8に関する新技術の中で、 Stratis は比較的多くの情報が公開されているように見受けられました。 今回はこの Stratis について調査してみました。

Stratisとは?

f:id:uhm3:20181213152902j:plain
Stratis Logo

公式サイトのFAQによると、

It’s not a traditional filesystem like ext4, XFS, or FAT32. Stratis manages block devices and filesystems to support features akin to “volume-managing filesystems” (VMFs) like ZFS and Btrfs

ということで Stratis は、 ZFS や Btrfs のような ボリューム(≒ブロックデバイス)管理機構を持った "volume-managing filesystems” (VMFs) という位置付けのソフトウェアになります。

古典的なFSは、1つのボリュームから1つのFSを作るものになっています(1:1)。 一方VMFsでは、複数のボリュームをまとめて一つのプールを作り、そこからFSを作成する(N:M)ことができます。

他のVMFsとの違いは?

一番の大きな違いは、「Stratis は XFS(VMFsでない古典的なFS) と DeviceMapper とをまとめて扱えるようにしたラッパーである」ということです。 これらを制御するために、ユーザースペースでストレージ管理・監視デーモン(stratisd)が動作しています。

デーモンとの通信手段は、現在のところ D-Bus API と CLI が実装されています。 将来的には API を拡張して、Ceph・Amazon EBS・Kubernetes CSI といった新しいストレージ技術との連携容易性を見込んでいるとのことです。

使ってみた

現時点で Stratis version 1.0 がリリース済で、Fedora29から使えるようになっています。
せっかくなので、ローカルのVirtualBoxで環境を作って試してみました。

  • host: MacBook Pro (13-inch, 2017)
    • 2cores 2.3GHz Core i5
    • 16GB LPDDR3
    • 250 GB SSD
  • guest: Fedora 29 Server x64
    • 1cpu
    • 8GB memory
    • 20GB 可変サイズ vdi

インストール&デーモン起動

インストールするパッケージが、デーモンとCLIで2つある点に注意しましょう。

[root@localhost ~]# dnf install -q -y stratisd stratis-cli
[root@localhost ~]# systemctl start stratisd
[root@localhost ~]# systemctl status stratisd
● stratisd.service - A daemon that manages a pool of block devices to create flexible file systems
   Loaded: loaded (/usr/lib/systemd/system/stratisd.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2018-12-13 15:41:32 JST; 5s ago
     Docs: man:stratisd(8)
 Main PID: 1242 (stratisd)
    Tasks: 1 (limit: 4915)
   Memory: 884.0K
   CGroup: /system.slice/stratisd.service
           └─1242 /usr/libexec/stratisd --debug

1213 15:41:32 localhost.localdomain systemd[1]: Started A daemon that manages a pool of block devices to create flexible file systems.
1213 15:41:32 localhost.localdomain stratisd[1242]: DEBUG libstratis::stratis::buff_log: BuffLogger: pass_through: true hold time: none
1213 15:41:32 localhost.localdomain stratisd[1242]:  INFO stratisd: Using StratEngine
1213 15:41:32 localhost.localdomain stratisd[1242]: DEBUG stratisd: Engine state:
1213 15:41:32 localhost.localdomain stratisd[1242]: StratEngine {
1213 15:41:32 localhost.localdomain stratisd[1242]:     pools: {},
1213 15:41:32 localhost.localdomain stratisd[1242]:     incomplete_pools: {},
1213 15:41:32 localhost.localdomain stratisd[1242]:     watched_dev_last_event_nrs: {}
1213 15:41:32 localhost.localdomain stratisd[1242]: }
1213 15:41:32 localhost.localdomain stratisd[1242]:  INFO stratisd: DBUS API is now available

プール作成〜ファイルシステム作成

最も基本的なオペレーションである、プール作成からFS作成までをやってみます。

今回は実験用に loopback デバイス(ファイルをブロックデバイスとして見せるもの)を使いますが、 本来は通常のブロックデバイス(例:/dev/sdb)を利用して下さい。

0.実験用 loopback デバイスを作成

[root@localhost ~]# dd if=/dev/zero of=./data0.dat bs=1M count=1024
1024+0 レコード入力
1024+0 レコード出力
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 1.15933 s, 926 MB/s
[root@localhost ~]# dd if=/dev/zero of=./data1.dat bs=1M count=1024
1024+0 レコード入力
1024+0 レコード出力
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 2.07796 s, 517 MB/s
[root@localhost ~]# losetup -f ./data0.dat
[root@localhost ~]# losetup -f ./data1.dat
[root@localhost ~]# losetup
NAME       SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE       DIO LOG-SEC
/dev/loop1         0      0         0  0 /root/data1.dat   0     512
/dev/loop0         0      0         0  0 /root/data0.dat   0     512

1.複数のデバイスからなる Stratis のプールを作成

[root@localhost ~]# stratis pool create p0 /dev/loop0 /dev/loop1
[root@localhost ~]# stratis pool list
Name    Total Physical Size  Total Physical Used
p0                    2 GiB               56 MiB
[root@localhost ~]# stratis blockdev list
Pool Name  Device Node    Physical Size   State  Tier
p0         /dev/loop0             1 GiB  In-use  Data
p0         /dev/loop1             1 GiB  In-use  Data

2.Stratis のプールから複数のファイルシステムを作成&マウント

[root@localhost ~]# stratis filesystem create p0 fs0
[root@localhost ~]# stratis filesystem create p0 fs1
[root@localhost ~]# stratis filesystem create p0 fs2
[root@localhost ~]# stratis filesystem list
Pool Name  Name  Used     Created            Device
p0         fs0   546 MiB  Dec 13 2018 15:47  /stratis/p0/fs0
p0         fs1   546 MiB  Dec 13 2018 15:49  /stratis/p0/fs1
p0         fs2   546 MiB  Dec 13 2018 16:14  /stratis/p0/fs2
[root@localhost ~]# mkdir mnt{0,1,2}
[root@localhost ~]# mount /stratis/p0/fs0 ./mnt0
[root@localhost ~]# mount /stratis/p0/fs1 ./mnt1
[root@localhost ~]# mount /stratis/p0/fs1 ./mnt2
[root@localhost ~]# df -Th ./mnt{0,1,2}
ファイルシス                                              タイプ サイズ  使用  残り 使用% マウント位置
/dev/mapper/stratis-1-92d(中略)e68-thin-fs-0c8(中略)0e0 xfs      1.0T  1.1G 1023G    1% /root/mnt0
/dev/mapper/stratis-1-92d(中略)e68-thin-fs-f7f(中略)51a xfs      1.0T  1.1G 1023G    1% /root/mnt1
/dev/mapper/stratis-1-92d(中略)e68-thin-fs-0c5(中略)89e xfs      1.0T  1.1G 1023G    1% /root/mnt2

ここでは 1GB の loopback デバイス x2 から作ったプールから、1TB の xfs ファイルシステム x3 を作れています。 これは、プールが thin-provisioning(実際に必要とされるまで実領域を確保しない)の機能を持っているためです。*1

後からプールにブロックデバイスを足してあげることで、上限である1TBまで使えるようになります。 足りない状態で使い続けるといつか必ず write I/O Error が発生するので、この状態での実用にはリスクがあります。

その他にできること

現在の実装では、プール作成とファイルシステム作成以外にも以下のことが可能です。

プールへのキャッシュデバイスの追加
[root@localhost ~]# dd if=/dev/zero of=./cache.dat bs=1M count=1024
1024+0 レコード入力
1024+0 レコード出力
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.947921 s, 1.1 GB/s
[root@localhost ~]# losetup -f cache.dat
[root@localhost ~]# losetup -l
NAME       SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE       DIO LOG-SEC
/dev/loop1         0      0         0  0 /root/data1.dat   0     512
/dev/loop2         0      0         0  0 /root/cache.dat   0     512
/dev/loop0         0      0         0  0 /root/data0.dat   0     512
[root@localhost ~]# stratis pool add-cache p0 /dev/loop2
[root@localhost ~]# stratis blockdev list
Pool Name  Device Node    Physical Size   State   Tier
p0         /dev/loop0             1 GiB  In-use   Data
p0         /dev/loop1             1 GiB  In-use   Data
p0         /dev/loop2             1 GiB  In-use  Cache
[root@localhost ~]# stratis pool list
Name    Total Physical Size  Total Physical Used
p0                    2 GiB                2 GiB

I/Oが高速なブロックデバイス(SSDなど)を、キャッシュ用デバイスとしてプールに登録することができます。*2 キャッシュ用であるためプール自体のサイズは変化しません。

今回は擬似的な loopback デバイスを使っているため性能は測りませんが、どのくらいの効果が出るのか実測して使いましょう。

ファイルシステムのスナップショット作成
[root@localhost ~]# echo foobar > ./mnt0/hoge.txt
[root@localhost ~]# stratis filesystem snapshot p0 fs0 fs0-snap
[root@localhost ~]# stratis filesystem list
Pool Name  Name      Used     Created            Device
p0         fs0       546 MiB  Dec 13 2018 16:25  /stratis/p0/fs0
p0         fs0-snap  546 MiB  Dec 13 2018 16:56  /stratis/p0/fs0-snap
[root@localhost ~]# mkdir mnt0s
[root@localhost ~]# mount /stratis/p0/fs0-snap ./mnt0s
[root@localhost ~]# tree mnt0*
mnt0
└── hoge.txt
mnt0s
└── hoge.txt

0 directories, 2 files
[root@localhost ~]# echo fuga >> ./mnt0/hoge.txt
[root@localhost ~]# echo moge >> ./mnt0s/hoge.txt
[root@localhost ~]# head mnt0*/*
==> mnt0/hoge.txt <==
foobar
fuga

==> mnt0s/hoge.txt <==
foobar
moge

ある時点のファイルシステムの状態を静止点(=スナップショット)として残すことができます。 スナップショットをマウントすることで、改めて中のファイルを変更することもできます。*3

サポート予定の機能

公式の Whitepaper によると、今後も様々な機能がサポートされていくようです。
個人的に気になるものを以下に抜粋してみました。

  • version 2.0
    • raid 1/5/6/10
    • cache raid 1
    • Write through cache
    • Quotas
  • version 3.0
    • Send/Receive
    • Compression
    • Encryption
    • Dedup
  • version 4.0
    • Change a pool’s redundancy level
    • Tag-based blockdev and filesystem classification/grouping
    • Mirroring across partitions within a pool, for multi-site or across hw failure domains (shelves/racks)
    • Support for byte-addressible persistent memory

所感

今回は、 RHEL8 から採用が予定されている新しいストレージ管理ソフトウェア Stratis について、その使い方を紹介しました。

XFS も DeviceMapper も従来から存在する技術であり、個別に利用することは可能でした。 しかしながら、これらを適切な方法・順番で構成してシステムを整合させるためには、利用者側に求めるハードルが高いものだったと思います。*4 それだけに、Stratis の「ファイルシステムとブロックデバイスをまたがるラッパーとして統一的なI/Fを作ろう」という試みには価値があると感じています。

現状 (version 1.0) ではまだ機能が少なく用途も限られますが、次の version 2.0 で raid が使えるようになると一気に実用度が上がってくると思います。 以降でサポート予定の機能を見ても、古今のあらゆるストレージスタックを取り込もうとしていることがわかります。

インフラ技術者として、今後の進展と進化に注目していきたいと思います。

余談:注目したいポイント

Stratis の面白いポイントとして、その中核となるデーモンの実装に Rust が使われていることが挙げられます。

ストレージ管理というOSプラットフォームの根幹にあるソフトウェアを、軽量さと安全性が謳われる Rust で実装するのは理に適っていると思います。 こんなところにも新しさと挑戦していく姿勢とを感じることができて、とても興味深く感じました。

みなさんも一度、コードを覗いてみることをお勧めします。

github.com

We are hiring!

というわけで(?)、エムスリーにSREとしてJoinしてから一ヶ月半が過ぎました。

新しい職場で新しい仲間と新しい仕事をするということで、当初は少なからず身構えていました。 しかし蓋を開けてみると、皆がやる気に満ちていて、技術への理解が深いことがわかり、今ではとても過ごしやすい環境だと思っています!

社内勉強会のTechTalkに参加すると、エンジニアリンググループの雰囲気がわかりやすく伝わると思います。 ご興味を持たれた方は、↓のリンク先から参加登録して足をお運び下さい。 カジュアル面談もおすすめです!

jobs.m3.com

*1:実際のバックエンドでは、 DeviceMapper の dm-thin が使われています

*2:バックエンドで使われているのは DeviceMapper の dm-cache のようです

*3:この機能にもバックエンドには dm-thin が使われています。ストレージにおける thin-provisioning と snapshot は「書き込まれた増分/差分を管理する」という内部動作が近しく、 dm-thin はその両方の I/F を提供しています。

*4:ストレージ周りで操作をミスしたりバグを踏んでしまうと、多くの場合データが欠損する・・・というのもハードルを高くしています。