2011年11月29日火曜日

なぜオンライン EXT3 の LVM2 スナップショット & バックアップは問題なく動くのか?

お疲れ様です、サイオス 那賀です。新書本風のタイトルにしてみました。

最初に、私の自宅サーバの、えらく大雑把なバックアップを紹介しようと思います。日に一回、ルート直下のスナップショットを、まるごと別のハードディスクに rsync で増分バックアップしています。システムは以下のようにマウントされています。/ 直下が LVM であり、EXT4 でマウントされています。

$ mount | grep /dev/mapper
/dev/mapper/vg_main-lv_main on / type ext4 (rw,errors=remount-ro)
/dev/mapper/vg_sub-lv_sub on /sub type ext4 (rw)

以下は、1 日 1 回実行されるバックアップスクリプトです。LVM スナップショットをリードオンリーでマウントし、rsync でコピーするだけの簡単なものです。

$ cat /etc/cron.daily/backup-snapshot
#!/bin/sh

mntpnt=/mnt/tmp

# /vm/ は大きいので、日曜日にだけバックアップ
foptvm=
# From Sunday, 0-indexed
test $(date +%w) != 0 && foptvm="$foptvm --exclude /vm/"

mkdir -p /sub/_
lvcreate --size 30G --snapshot --name lv_snap /dev/vg_main/lv_main
mount -o ro /dev/vg_main/lv_snap $mntpnt
if test -d $mntpnt/proc
then
  rsync -avr --delete $foptvm $mntpnt/ /sub/_
fi
umount $mntpnt
lvremove -f /dev/vg_main/lv_snap

当初は、DB ごとに個人データごとにと、個別にバックアップをとっていたのですが、サーバの用途が増えてきたためだんだん面倒くさくなってきてしまい、このような丸ごとバックアップに落ち着きました。問題なく動いていたので、これで正しいのだろうと思っていたのですが、ふとログを見ると、以下のようなメッセージが出ていました。

$ grep EXT4 /var/log/messages
Nov XX 06:25:03 queen kernel: [10216804.075357] EXT4-fs (dm-3): orphan cleanup on readonly fs
Nov XX 06:25:03 queen kernel: [10216804.151685] EXT4-fs (dm-3): 43 orphan inodes deleted
Nov XX 06:25:03 queen kernel: [10216804.151689] EXT4-fs (dm-3): recovery complete
Nov XX 06:25:04 queen kernel: [10216804.249053] EXT4-fs (dm-3): mounted filesystem with ordered data mode. Opts: (null)
Nov YY 06:25:03 queen kernel: [10303060.217676] EXT4-fs (dm-3): orphan cleanup on readonly fs
Nov YY 06:25:03 queen kernel: [10303060.542436] EXT4-fs (dm-3): 45 orphan inodes deleted
Nov YY 06:25:03 queen kernel: [10303060.542441] EXT4-fs (dm-3): recovery complete
Nov YY 06:25:03 queen kernel: [10303060.648882] EXT4-fs (dm-3): mounted filesystem with ordered data mode. Opts: (null)
Nov ZZ 06:25:02 queen kernel: [10389317.017146] EXT4-fs (dm-3): orphan cleanup on readonly fs
Nov ZZ 06:25:02 queen kernel: [10389317.117018] EXT4-fs (dm-3): 45 orphan inodes deleted
Nov ZZ 06:25:02 queen kernel: [10389317.117023] EXT4-fs (dm-3): recovery complete
Nov ZZ 06:25:03 queen kernel: [10389317.215482] EXT4-fs (dm-3): mounted filesystem with ordered data mode. Opts: (null)

特に気になるのが「~ orphan inodes deleted」です。リードオンリーでマウントしているはずなのに、EXT4 のクリーンアップが動いて、ファイルシステムに変更を加えているように見えます。この分だと、ジャーナルのリプレイもしているのではないでしょうか? むしろジャーナルのリプレイができないとなると、マウントしたままの EXT4 のブロックデバイスイメージから取っているスナップショットですので、ファイルシステムには不整合が生じているのでは? そもそも、LVM のスナップショットって書きこめるの?

と、疑問が出てきてしまったので、検証してみました。まずは、「LVM のスナップショットに書き込めるのか?」から。

root@queen:~# lvcreate --size 30G --snapshot --name lv_snap \
 /dev/vg_main/lv_main
  Logical volume "lv_snap" created
root@queen:~# mount -o rw /dev/vg_main/lv_main /mnt/tmp
root@queen:~# ls -l /mnt/tmp/hoge
ls: cannot access /mnt/tmp/hoge: No such file or directory
root@queen:~# echo hoge > /mnt/tmp/hoge
root@queen:~# cat /mnt/tmp/hoge
hoge
root@queen:~# umount /mnt/tmp/
root@queen:~# lvremove -f /dev/vg_main/lv_snap
  Logical volume "lv_snap" successfully removed

余裕で書き込めますね。知らなかった…。「LVM HOWTO」の「Snapshots」の項に、以下のようにあります。

In LVM2, snapshots are read/write by default. Read/write snapshots work like read-only snapshots, with the additional feature that if data is written to the snapshot, that block is marked in the exception table as used, and never gets copied from the original volume.

LVM2 になってからは、スナップショットの差分領域は、スナップショット元からの差分を保持すると同時に、スナップショットへの書き込み差分も保持するようになっているそうです。静的なスナップショットというよりも、動的に書き込める、揮発的なブランチのようなものですね。

さて、LVM スナップショットに書き込めることは分かったので、次は、リードオンリー・マウントでも EXT4 がマウント時にファイルシステムの修復を行うかどうか、です。

余談なのですが、最近の Linux は I/O フリーズの機能を持っています。ファイルシステムを一貫性のある状態に移行させてから一時「凍結」し、バックアップやコピーをとるための機能です。これを使えば、以下のようにきれいなスナップショットがとれます。

  • ioctl(2) に FIFREEZE で、I/O を止め、一時的にファイルシステムを一貫性のある状態に保つ
  • LVM でブロックデバイスのスナップショットをとる
  • FITHAW で、フリーズを解除
  • スナップショットをマウントし、ゆっくりと rsync ででもコピーをとる
  • アンマウントして、スナップショットを開放

しかし残念ながら、今の LVM などでは、この機能を使っていません…か? FIFREEZE 等の呼び出しがないことから、てっきり使っていないと思っていたのですが、RHEL6 などで FIFREEZE/FITHAW の ioctl() を発行するためのコマンド fsfreeze(8) の man を参照すると、以下のように書かれています。

fsfreeze is unnecessary for device-mapper devices. The device-mapper (and LVM) automatically freezes filesystem on the device when a snap-shot creation is requested. For more details see the dmsetup(8) manpage.

LVM2 のコードを見てみると(かなり読みづらいコードなのですが)、lvcreate(8) でスナップショットを作成すると、device mapper の「ブロックデバイスに対して」、DM_DEV_SUSPEND_CMD で ioctl() を呼んでいます (これは、drivers/md/dm-ioctl.c まわりのコードです。対して、ファイルシステムへのコードは linux/fs/ioctl.c:ioctl_fsfreeze() にあり、FIFREEZE での ioctl() が、「ファイルシステム上のノードに対して」発行されます)。とはいえ、結果的には、両者とも同一のスーパーブロックに対して freeze_bdev() を実行することになります。ブロックデバイスのくせして、自分の上に載っているファイルシステムにまで干渉するとは、何だか妙な感じがしますが、理にかなってはいます。

よって、LVM2 でスナップショットを取る前には、一瞬 I/O を停止して、ファイルシステムを整合性を保った状態まで持って行ってからスナップショットを作成しています。

以上でスナップショットについては解決したのですが、では、異常終了時の EXT3 はどうなんでしょう。結論から言うと、「[RFC, PATCH 0/6] ext3: do not modify data on-disk when mounting read-o」や「'Add a norecovery option to ext3/4?' - MARC」を見ると分かるように、実は「-o ro」オプションをつけてマウントしても、EXT3/EXT4 は、可能であれば(デバイスが書き込み可能であれば)ジャーナルのリプレイと orphan inode の切り落としをしてしまいます。ソース中では "really_read_only" のフラグで分岐しています。

linux-2.6.32/fs/ext4/super.c:

static int ext4_load_journal(struct super_block *sb,
                             struct ext4_super_block *es,
                             unsigned long journal_devnum)
{
    ...
    int really_read_only;
    ...
    really_read_only = bdev_read_only(sb->s_bdev);
    ...
    if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
        if (sb->s_flags & MS_RDONLY) {
            ext4_msg(sb, KERN_INFO, "INFO: recovery "
                "required on readonly filesystem");
            if (really_read_only) {
                ext4_msg(sb, KERN_ERR, "write access "
                    "unavailable, cannot proceed");
                return -EROFS;
            }
            ext4_msg(sb, KERN_INFO, "write access will "
               "be enabled during recovery");
        }
    }
    ...
}

以上をまとめますと、

  • LVM2 では、元 LV のダーティバッファはスナップショットにも反映される
  • LVM2 のスナップショットには、書き込みができる
  • スナップショットはブロックデバイスでありながら、その上層のファイルシステムと示し合わせて、一貫性のある状態でのスナップショットを取ってくれる
  • EXT3/EXT4 の "-o ro" マウントは、(journal リプレイと) orphan inode 切り落としをする

以上から、EXT3/EXT4 の、ある瞬間のスナップショットを LVM2 でとって、それをリードオンリーマウントしてコピーをとっても、一貫性の点では問題はないということですね。

やれやれ、ZFS や btrfs のような、シャドウコピーで手軽にファイルシステムレベルでスナップショットを利用できるようになれば、LVM を事前に用意する必要もないので、はるかに話は簡単になるんですが。早くデフォルトにならないかなぁ。

ではまた。

0 件のコメント:

コメントを投稿