この記事は、LVM スナップショットの領域を使いきってしまった人のための記事です。
きっかけ
今朝、LVM スナップショットの領域があふれている状態で発見されました。少なくとも1ヶ月以上は放置されていたようです。発見が遅れてしまったため、事件発生時のログが 1 つも残ってませんでした。
LVM スナップショットの仕組みを考えれば、スナップショット領域があふれた場合であってもスナップショット取得対象の LV(以降、“元の LV” とします)には影響ないだろ〜と思っていました。しかし、インターネットを眺めていると「元のファイルもつかえなくなる」という情報もちらほらありました。
これによって結構不安になってしまいました。しかも、今まで LVM スナップショット領域があふれたことがなかったので、自分の推測に確信が持てませんでした。こんな状況で lvremove は叩けません。 今回は、この不安を取り除こうと思い、今回の事件について検証をしました。
LVM スナップショットとは?
Linux では、 LVM を用いることでスナップショットという便利な機能を利用することができます。スナップショットについて、図解でわかりやすい記事を発見したので貼っておきます。これを説明の代わりとします。LVM スナップショットがうろ覚えな方は、下記の記事を読んだあとにこのエントリを読み進めていただくと本エントリの内容がわかりやすくなると思います。
登場人物が多いのでポイントをまとめると
- 物理デバイスの上に物理ボリューム作ってさらにその上にボリュームグループ(VG)を作ると、その上に論理ボリューム(LV)を作れるようになる
- スナップショットも VG の領域を消費して作られる
- スナップショットの対象は既存の LV
- スナップショット領域では、実データへのポインタを保持する
- スナップショット領域の消費は、実データが変更されたタイミングで発生する
- 更新前のデータを退避するため
知りたいこと
今回の検証において知りたいことは以下の2点になります。
- スナップショット領域が溢れたあとも、これまで通り元の LV へ読み書きできるのか
- 上記を実施後、スナップショットを削除したら何か副作用が発生するのか
実験の内容
- 環境
- OS: CentOS 6.4
- カーネルバージョン: 2.6.32-431.17.1
- LVM バージョン: 2.02.100
- ファイルシステム: ext4
- ボリューム情報
- VG 名: vg_bonjour01_2
- 総容量(VG Size): 2TB
- 空き容量(Free PE): 500GB
- 元の LV 名: LogVol00
- VG の領域の 1.5TB を割り当て
- /backup にマウント済み
- スナップショット作成時の LV 名: test_snap
- VG の領域の 32MB を割り当て
- VG 名: vg_bonjour01_2
- 書き換え対象のファイル: /backup/100MB.img
実験で利用する VG の総容量は 2TBで、すでに 1.5 TB の容量を LogVol00 に割り当て済みです。そのため、VG の残りの空き容量は 500GB となります。空き容量としては十分ですね。本番運用ではスナップショット領域を大きめに確保するのが一般的ですが、今回の実験ではスナップショットの領域を簡単に溢れさせるために 32 MB だけ確保します。
スナップショット領域があふれさせるまでの流れ
- スナップショット取得
- 元の LV 上の対象ファイル(/backup/100MB.img)に対して、32MB 以上の領域を必要とする書き換えを実行
- このとき、スナップショット領域に変更前のデータが退避される
- 書き換えが発生することで変更前のデータが退避されるが、やがてスナップショット領域を食いつぶしてあふれる
- 元の LV 上の対象ファイルに対して書き込み
- スナップショット領域を開放
※ スナップショットにて取得したデータ自体を操作することがないので、スナップショット領域をマウントしたりはしません。
実験の過程と結果
1. VG の確認
VG の領域の確認。空き容量(VFree)は 500GB。
# vgdisplay -C vg_bonjour01_2
VG #PV #LV #SN Attr VSize VFree
vg_bonjour01_2 1 1 0 wz--n- 1.82t 500.00g
2. スナップショット取得
VG の 32 MB を確保して LogVol00 を対象にスナップショット作成。スナップショットの LV 名は test_snap。
# lvcreate -s -L 32M -n test_snap /dev/vg_bonjour01_2/LogVol00
Logical volume "test_snap" created
スナップショット作成後の VG。VFree が 500.00 → 499.97 に減ってることがわかる。
# vgdisplay -C vg_bonjour01_2
VG #PV #LV #SN Attr VSize VFree
vg_bonjour01_2 1 2 1 wz--n- 1.82t 499.97g
作成した LV の空き容量を確認。Data% は使用領域を表す。今は全然消費していないのでほぼ 0 %。
# lvdisplay -C /dev/vg_bonjour01_2/test_snap
LV VG Attr LSize Pool Origin Data% Move Log Cpy%Sync Convert
test_snap vg_bonjour01_2 swi-a-s-- 32.00m LogVol00 0.04
LV のステータスを確認。元の LV とスナップショット用の LV の両方が ACTIVE、つまり利用可能な状態。
# lvscan | grep vg_bonjour01_2
ACTIVE Original '/dev/vg_bonjour01_2/LogVol00' [1.33 TiB] inherit
ACTIVE Snapshot '/dev/vg_bonjour01_2/test_snap' [32.00 MiB] inherit
3. 元の LV 上の対象ファイルをたくさん書き換える
dd コマンドでランダムにファイルを書き換える。書き換え量は 100MB となる。 エラーなく書き換えが完了したことを確認できた。
# dd if=/dev/urandom of=/backup/100MB.img bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 11.7947 s, 8.9 MB/s
# echo $?
0
書き換え対象のハッシュ値をあとで比較するために取得。
# md5sum /backup/100MB.img
d0e90d10b6c48ce999183ba9743c95ba /backup/100MB.img
3. スナップショット領域があふれたことを確認
作成した LV の空き容量を確認。やばそうなエラーを4行吐いている。スナップショットの使用領域(Data%)が 100% になっている。 これにより、スナップショット領域と等しい書き込み、または、それを超える書き込みが行われたことが確認できた。
# lvdisplay -C /dev/vg_bonjour01_2/test_snap
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 1463522623488: 入力/出力エラーです
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 1463522680832: 入力/出力エラーです
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 0: 入力/出力エラーです
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 4096: 入力/出力エラーです
LV VG Attr LSize Pool Origin Data% Move Log Cpy%Sync Convert
test_snap vg_bonjour01_2 swi-I-s-- 32.00m LogVol00 100.00
システムログを確認。これにより、 32MB を超えて領域を確保しようとして失敗したことを確認できた。つまり、あふれた。
# less /var/log/messages
Feb 14 15:23:46 bonjour-01 kernel: device-mapper: snapshots: Invalidating snapshot: Unable to allocate exception.
LV のステータスを確認。またしてもやばそうなエラーを4行吐いている。 スナップショット用の LV だけでなく、元の LV についても、ステータスが Active ではなく inactive になってる。ひやひやする。 なんとなく返り値確認したら 0 だった。ステータス関係ないのね。。
# lvscan
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 1463522623488: 入力/出力エラーです
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 1463522680832: 入力/出力エラーです
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 0: 入力/出力エラーです
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 4096: 入力/出力エラーです
inactive Original '/dev/vg_bonjour01_2/LogVol00' [1.33 TiB] inherit
inactive Snapshot '/dev/vg_bonjour01_2/test_snap' [32.00 MiB] inherit
# echo $?
0
4. 元の LV 上の対象ファイルを書き換え
スナップショット領域があふれた状態で元の LV 上のファイルを書き換えてみる
# dd if=/dev/urandom of=/backup/100MB.img bs=1M count=100
書き換え対象のハッシュ値を確認。事前に取得したハッシュ値と比較したところ異なっていため、 データの内容が書き換わっていることが確認できた。 また、コマンドが成功しているので 読み込みができることも確認できた。
# md5sum /backup/100MB.img
2f282b84e7e608d5852449ed940bfc51 /backup/100MB.img
※ 2. にて確認したときのハッシュ値は d0e90d10b6c48ce999183ba9743c95ba
5. スナップショット領域の開放
エラーが怖い。でも successfully と出力されているので、無事に開放されたっぽい。
# lvremove /dev/vg_bonjour01_2/test_snap
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 1463522623488: 入力/出力エラーです
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 1463522680832: 入力/出力エラーです
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 0: 入力/出力エラーです
/dev/vg_bonjour01_2/test_snap: read failed after 0 of 4096 at 4096: 入力/出力エラーです
Do you really want to remove active logical volume test_snap? [y/n]: y
Logical volume "test_snap" successfully removed
LV のステータスを確認。inactive から ACTIVE になっていた。 また、スナップショット用の LV が表示されていない。これにより開放されていることが確認できた。
# lvscan | grep vg_bonjour01_2
ACTIVE '/dev/vg_bonjour01_2/LogVol00' [1.33 TiB] inherit
書き換え対象のハッシュ値を確認。開放前(4.)に取得したハッシュ値と一致していることがわかる。 これにより、 スナップショット領域を開放してもデータの変更内容が保持されることが確認できた。
# md5sum /backup/100MB.img
2f282b84e7e608d5852449ed940bfc51 /backup/100MB.img
まとめ
LVM スナップショットの領域を使い切った場合、元の LV 上のデータはどうなるのかを調べました。
- 使いきった状態でも元の LV では普通に読み書きができ、書き込み内容はその後も保持されました
- スナップショット領域をあふれさせ、それを片付けるまでの間、元の LV 上のデータには特に影響はでませんでした
- 元の LV のステータスが inactive になるのなんなんだ
- 不安が解消されたので気持ちよく月曜日を迎えられそう
- 人生甘くないのでスナップショット領域があふれたらどうなるかくらいは知ってて損はないと思う
追記
LVM を勉強する上で、以下の書籍にお世話になりました。わかりやすいのでオススメです。LVM については 3 章に記載されています。