ストレージアーキテクチャの比較:従来のパーティション vs 標準LVM vs シンプール
半年前、私たちのデータベースクラスターは限界に達しました。4台のプライマリPostgreSQLノードで従来のGPTパーティションテーブルを運用しており、各ノードには500 GBのNVMeドライブが搭載されていました。
/var/lib/postgresqlのディスク使用率が90%を超えると、リサイズ作業はトラブルの種でした。深夜23時のメンテナンス枠を確保し、ロードバランサーからノードを切り離し、ボリュームをアンマウントした上で、ファイルシステムのヘッダーが破損しないことを祈りながらpartedを実行する――。毎週2時間ものエンジニアリング工数が、この手作業のディスクリサイズに奪われていたのです。
Logical Volume Manager(LVM)への移行が、この苦痛を解消してくれました。現代のLinuxでブロックストレージを設計する場合、一般的に次の3つの選択肢があります。
- 従来の固定パーティション(MBR/GPT):ブロックの境界が単一ドライブ上の連続したセクターに厳格に固定されます。パーティションを拡張するには隣接する空き領域が必要であり、手動でのパーティションテーブル編集やオフラインでのアンマウントが避けられません。
- 標準LVM(シックプロビジョニング):未加工のドライブを物理ボリューム(PV)とし、それらをボリュームグループ(VG)に統合した上で、論理ボリューム(LV)に分割します。ブロックは事前に確保されます。LVのオンライン拡張は可能ですが、ボリューム間で空き容量を簡単に共有したり、ストレージをオーバーコミットしたりすることはできません。
- シンプロビジョニングLVM(LVMシンプール):ボリュームは共有の物理プールからオンデマンドで64 KB〜1 MBのチャンクを消費します。500 GBのプールに対して2 TBの仮想容量を割り当てることができ、作成初期のブロックフットプリントがゼロの特定時点(Point-in-Time)スナップショットを取得可能です。
コンテナホスト、動的なステージング環境、即時バックアップが求められるデータベースクラスターにおいて、シンプロビジョニングLVMは比類のない運用の俊敏性をもたらします。
実録:本番環境でLVMを6か月運用して得た知見
18台のアプリケーションノードおよびデータベースノードをLVM上で運用したことで、その最大の強みと注意すべき弱点の双方が浮き彫りになりました。
得られたメリット
- 無停止のオンライン拡張:
ext4やXFSなどのファイルシステムを使用すれば、標準LVやシン論理ボリュームの拡張を瞬時に実行できます。実行中のPostgreSQLトランザクションやユーザーのファイルアップロードが中断されることはありません。エンドユーザーに影響を与えることなく作業が完了します。 - 1秒未満のアトミックスナップショット:シンスナップショットはコピーオンライト(CoW)のメタデータポインタを利用します。大規模なスキーママイグレーション直前に稼働中の120 GBのデータベースボリュームを固定する処理は、通常のファイルコピーでは8〜12分かかるところ、わずか約15ミリ秒で完了します。
- ディスクの無駄を徹底排除:50 GBを割り当てたステージング環境のマイクロサービスでも、実際には4 GBしか使っていないことがよくあります。シンプールは実データが書き込まれたセクターのみを消費するため、クラスター全体で1.2 TB以上の未割り当て領域を節約できました。
- シームレスなストレージ拡張:容量が逼迫した際も、サーバーのシャーシに1 TBのNVMeドライブを追加し、
pvcreateを実行して既存のボリュームグループに組み込むだけで完了します。稼働中のパーティションを再フォーマットする必要はありません。
トレードオフと注意点
- プール枯渇の罠:オーバープロビジョニングにより、400 GBの物理プール上に1 TBの仮想領域を割り当てることができます。しかし使用量が急増してシンプールが100%に達すると、カーネルは書き込み操作を即座に停止します。適切に処理されない書き込み停止は、深刻なファイルシステム破損を引き起こす恐れがあります。
- メタデータ修復の複雑さ:シンプールはペアとなる内部データとメタデータのサブボリュームに依存しています。破損したメタデータを
thin_checkやthin_repairで復旧するには、/dev/sdb1のような通常の破損パーティションを修正するよりもはるかに深いストレージデバッグの知識が求められます。 - 初回書き込み時のレイテンシオーバーヘッド:シンプールは新しいセクターへの書き込み時にチャンクを動的に割り当てるため、あらかじめ割り当て済みのシックプロビジョニングブロックと比較して、純粋なランダム書き込みスループットで3%〜7%のパフォーマンス低下が発生します。
本番環境で鍛え上げられたベストプラクティス設定
ログの急増によって監視外のプールが枯渇しかけ、サービス停止寸前の障害対応を経験した後、私たちはLinuxストレージの運用ベースラインを以下のルールとして標準化しました。
- 各ボリュームグループに20%の空き容量を確保する:VGのエクステントを最初から100%割り当てるのは避けてください。50 GB〜100 GBを予備として残しておくことで、容量不足に陥ったボリュームを数秒で拡張したり、インシデント対応時に一時的なクローンターゲットを割り当てたりできます。
- 縮小機能が必要な場合はext4を選択する:XFSは大規模な並行処理をきれいに処理しますが、拡張しかできず縮小は不可能です。後からディスク容量を解放する必要がある一時的なスパイクが発生するワークロードでは、オンライン拡張とオフライン縮小の双方が可能な
ext4が適しています。 - dmeventdによるプールの自動拡張を有効化する:プールの空き容量管理を人間の記憶に頼ってはいけません。
/etc/lvm/lvm.confでdmeventdの監視を有効化します。thin_pool_autoextend_threshold = 75およびthin_pool_autoextend_percent = 20と設定することで、書き込みが停止する前にシステムが自動的にプールを拡張するようにします。 - OSルートを動的プールから分離する:ルートファイルシステム(
/)は従来のシックプロビジョニングLV上に保持してください。暴走したログによってOSのコアユーティリティがクラッシュしないよう、アプリケーションデータ、Dockerボリューム、データベースディレクトリは専用のシンプールに隔離します。
Ubuntu 22.04 LTSを採用したデータベースホスト(16 vCPU、64 GB RAM、RAID 1構成のNVMeデュアルドライブ)において、この構成によりディスクプロビジョニングのオーバーヘッドが40%削減され、数時間を要していた業務中断メンテナンスがダウンタイムゼロの5分間の作業へと変わりました。
ステップ別:実装ガイド
以下の手順に従って、生の物理ブロックデバイスの登録、シンプールの構築、稼働中ファイルシステムのオンライン拡張、およびアトミックスナップショットの管理を実施します。
ステップ1:物理ボリューム(PV)とボリュームグループ(VG)の初期化
lsblkを使用してセカンダリストレージディスク(例: /dev/sdb)を確認します。未加工のデバイスをLVM物理ボリュームに変換し、vg_productionという名前の新しいボリュームグループに追加します。
# 生のディスクデバイスを初期化
sudo pvcreate /dev/sdb
# デフォルトの4MB物理エクステントを使用してボリュームグループを作成
sudo vgcreate vg_production /dev/sdb
# 空きエクステントと合計容量を確認
sudo vgs
ステップ2:稼働中の論理ボリュームをダウンタイムゼロで拡張する
既存のボリュームの容量が不足した際、アプリケーションの停止やディレクトリのアンマウントを行う必要は一切ありません。-r(または--resizefs)フラグを指定することで、論理ボリュームの境界拡張と基盤となるファイルシステムのサイズ変更を同時に実行するようLVMに指示できます。
# 稼働中のボリュームに20GBを追加し、ファイルシステムも同時にリサイズ
sudo lvextend -r -L +20G /dev/vg_production/lv_appdata
# またはボリュームグループの残りの空きエクステントの80%を割り当て
sudo lvextend -r -l +80%FREE /dev/vg_production/lv_appdata
df -h /var/wwwを実行して、更新されたボリュームサイズを確認します。接続の切断を一切引き起こすことなく、追加容量が即座に反映されます。
ステップ3:シンプールの構築とオンデマンドボリュームのマウント
シンプロビジョニングを導入するには、ボリュームグループ内に共有シンプールを作成します。このプールは、複数の仮想ディスクに対する共通の物理ブロックリザーブとして機能します。
# 'vg_production'内に'pool_thin'という名前の80GBの物理シンプールを割り当て
sudo lvcreate -L 80G -T vg_production/pool_thin
# その80GBのプールに対して仮想200GBのボリュームをプロビジョニング
sudo lvcreate -V 200G -T vg_production/pool_thin -n lv_webdata
# 仮想ボリュームをext4でフォーマット
sudo mkfs.ext4 /dev/vg_production/lv_webdata
# アプリケーションディレクトリにパーティションをマウント
sudo mkdir -p /var/www/uploads
sudo mount /dev/vg_production/lv_webdata /var/www/uploads
オペレーティングシステムには200 GBのパーティションとして認識されますが、アプリケーションがファイルの書き込みを開始するまで、物理プール上のストレージ消費量はゼロバイトのままです。
ステップ4:安全なデプロイのための即時スナップショット取得
大規模なソフトウェアリリースや未検証のデータベースマイグレーションを実行する前に、特定時点のイメージを取得します。シンスナップショットはコピーオンライトのポインタを介して変更を追跡するため、余分なディスク容量を消費することなく、わずか数ミリ秒で作成できます。
# 稼働中のボリュームのシンスナップショットを瞬時に取得
sudo lvcreate -s --name snap_webdata_pre_upgrade /dev/vg_production/lv_webdata
# スナップショットの割り当てとデータの差分を確認
sudo lvs vg_production
デプロイのスモークテストに合格したら、スナップショットを削除して追跡されていたブロックの差分データを解放します。
# 検証完了後にスナップショットを削除
sudo lvremove -y /dev/vg_production/snap_webdata_pre_upgrade
万が一マイグレーションに失敗してテーブルデータが破損した場合は、デプロイ前の状態にロールバックします。ボリュームをアンマウントし、マージ操作を実行して再マウントします。
# アクティブなファイル記述子の競合を防ぐためボリュームをアンマウント
sudo umount /var/www/uploads
# ボリュームをスナップショット取得時の状態に完全にロールバック
sudo lvconvert --merge /dev/vg_production/snap_webdata_pre_upgrade
# 復元されたデータを再マウント
sudo mount /dev/vg_production/lv_webdata /var/www/uploads
プールの健全性監視
シンプールの容量は常に注意深く監視してください。sudo lvsを実行すると、現在の消費率がData%列に表示されます。このメトリクスをPrometheusのnode_exporterに連携させるか、使用率が75%に達した時点でエンジニアリングチームに通知するアラートWebhookを設定しましょう。そうすることで、書き込みが停止する前にNVMeドライブを増設してプールを拡張するための十分な猶予が確保できます。

