機械学習 / データ分析

課題や運用方針など上流レイヤのことについて書く場所にする予定。変わるかも。

システム領域とデータ領域でボリュームを分けるべきか?

概要

ubuntuでストレージを設計、運用する際に、システム領域とデータ領域でボリューム(後述)を分けるべきかについて検討した結果を共有する。

注意:以下の検討では、著者の運用経験、知識の不足により重要な観点が漏れているかもしれません。変なことを言っていたら指摘をお願いします。

経緯

先日自作したPCにubuntuをインストールした。インストールしたストレージのサイズは2TBにも関わらず、デフォルトで利用できるストレージサイズは100GBしかなかった。 解決方法をネットで検索すると、「データボリュームを残量いっぱいまで拡張する*1」というものが多かった。個人的にこの解決方法(=単一ボリュームの大きなストレージを作る)が妥当なのかどうか判断ができなかったので、以下にあげる観点でこの対応の妥当性を検討した。

問題

1TBを超える大きなストレージを運用する場合、システム領域とデータ領域でボリュームを分けるべきか?

観点:単一のボリュームで運用する場合に想定するリスク:

  1. inode(後述)は枯渇しないか?
  2. 容量を超えるデータをダウンロードしたときに、システム領域で操作できなくなるのでは?

前提知識について

ubuntuの用語や概念について馴染みがない読者向けに、この記事で触れる用語や概念について大まかに説明しておく。すでに知っている読者はこの章は読み飛ばしても構わない。

inode

OSが管理しているディレクトリはツリーで表現された抽象的なデータ構造だが、実際にストレージに格納されたデータ上の区画とツリーの接点(=ディレクトリ)や葉(=ファイル)を対応させるためには、ファイルに対応するストレージの区画を表すポインタのようなメタデータが必要となる。それがinodeである。したがってinode数は作成されたファイルやディレクトリの個数に大まかに対応するubuntu 22.04で標準で利用されているext4ファイルシステムでは1 inode (=1ファイル/ディレクトリ)あたり256バイトを占有する。inode領域として確保するデータ領域の割合はブロックデバイスの作成時に固定されており、ext4のデフォルトの設定では全ディスク領域の約1.6%に当たる。なおこの割合は作成時に限りユーザが指定することもできる。このように、最初からinode領域のデータサイズが固定されているため、この領域を上回る数のファイルやディレクトリを作成した場合は、inodeを確保できなくなる。この状態を「inodeが枯渇する」と表現する

ボリューム

OSが管理するストレージの単位を表す用語で、Windowsの「ドライブ」に相当する概念。 ubuntuで採用されているLVM(Logical Volume Manager)では、実デバイスに対応する「物理ボリューム」と、実デバイスを抽象化した「論理ボリューム」がある。運用方法としては、未割り当ての物理ボリュームから論理ボリュームを1つ以上切り分けてディレクトリにマウントするのが一般的である。また、複数のボリュームをまとめた「ボリュームグループ」という管理単位がある。

例)ubuntu 22.04をデフォルトの設定内容でインストールした場合、ボリュームグループubuntu-vg、論理ボリュームubuntu-lvを作成する。

想定するリスクに対する回答

  1. ボリュームを拡張する場合、inodeの数もボリュームの容量に比例して拡張される*2ため、使用するボリュームの平均ファイルサイズがボリュームを新規作成した際に指定した「1 inodeあたりのディスク容量の割合*3」を下回らない限りinodeが枯渇することはない。
  2. システム領域とデータ領域のボリュームを分けることにより、障害の影響範囲を小さくすることができる(例:データ領域の容量を超えるデータをデータ領域にダウンロードしたとしても、システム領域の容量には余裕があるためシステムの操作に影響することがない)。ただし、システム領域の容量逼迫時は依然として操作ができなくなるリスクがある(例:システム領域にdockerコンテナを大量に作成した、pythonの仮想環境を大量に作成したなど)。したがって、この問題に対してはむしろシステム領域の容量を監視し、逼迫しそうになった場合にアラートを飛ばすような対応の方が本質的である

元の問題に対する回答

元の問題に対する著者の回答は以下である: 「ボリュームを分けて運用することはOS管理者の運用の選択肢の1つであって、分けなかったからといって、そのこと自体が問題になるわけではない」。

いかにそれぞれの運用方法のメリットとデメリットについて記述する。

  1. 単一ボリュームで運用する場合
    • (メリット) :設計や運用がシンプルになる。*4
    • (デメリット): 障害の影響範囲が大きい(例:ボリュームの容量を超えるデータをダウンロードしたためにシステム領域の操作に支障が出るなど)。
  2. 複数ボリュームで運用する場合
    • (メリット) : 障害の影響範囲を限定できる。また、ボリュームごとに最適なinode領域の割合を指定できるなどより柔軟な運用ができる。
    • (デメリット): ボリュームの使われ方を細かく指定することになるので、考えることが増える(例:どういう単位でボリュームを分割するか?、一つ一つのボリュームのinode領域の割合をどれくらいに設定するか?)

したがって、想定する使われ方で容量逼迫やinodeの枯渇のリスクがない(あるいは対応できる)なら単一ボリュームの運用でも問題ないと考える。逆に特定のプロセスが小さなファイルを大量に作成するような使われ方をして、かつそれがデータ容量の大部分を占めるようなケースではそのデータ用にボリュームを作り、inode領域の割合を大きめに設定して運用することを検討するべきだろう。

具体的なユースケース

以下ではボリュームを分けて運用する場合の具体的なユースケースについて簡単に述べる。なお、ubuntuマシンの利用方法としては機械学習の学習マシンとしての利用を想定している。

まず、機械学習においてディスクの容量を占有するデータには以下がある。

  1. 学習・評価用データ
  2. 学習環境用のdockerコンテナ
  3. 学習環境用のpython仮想環境
  4. 学習用のコードと依存パッケージ
  5. 学習済みモデルパラメータ

システム領域とは別にこれらのデータ専用のボリュームを作成することで、システム領域の拡張を抑制できる。

また、より細かく管理したい場合、あらかじめ想定される平均ファイルサイズに合わせてinode領域の割合を適切に設定することで、ディスク容量を節約することができる。例えば、2TBのストレージに、デフォルトの割合でinode領域を確保した場合、2000 GB * 1.6% = 32GBの領域をinode領域として確保するが、1-3, 5のデータの平均サイズは、15KBよりも大きいと想定されるので、その分inode領域を無駄に使用することになる。例えばImageNetなどの画像データの場合は数百KB程度、dockerコンテナの場合は数十〜数百MB程度だろう。これらのデータ用に用意したボリュームのinode領域の割合を最適化することで、使用できるストレージのサイズを(わずかに)増やすことができる。ただし、32GBは2TBに比べると十分小さな領域なので、これらを細分化して管理するコストと比較すると捨てても良いと割り切る選択肢もあるだろう。

参考資料

本記事を執筆する上で参考にした資料を共有する。

LVMの概念、運用方法についてはDigitalOceanが公開している以下のチュートリアルが参考になった。

  1. LVM の概念、用語、操作の紹介
  2. LVM を使用して Ubuntu 18.04 でストレージ デバイスを管理する方法

また、inodeについて概念的な理解を得るには以下の記事が個人的にわかりやすいと感じた。

  1. inode ってなんのためにあるの?

*1:https://askubuntu.com/questions/1106795/ubuntu-server-18-04-lvm-out-of-space-with-improper-default-partitioning

*2:実際にubuntu上で検証した結果: https://twitter.com/bilzrd/status/1585206483528343559

*3:デフォルトでは1 inodeあたり約15KBに設定されているようである。

*4:特に、inode領域の割合について言えば、デフォルトの1 inodeあたり15KBという割合は十分保守的に設定されているため、inode領域に使用する1.6%のデータ領域を税金と割り切るなら特に指定しなくても多くのケースでは問題とならないだろう。