2014年2月13日木曜日

ramdisk(/dev/ram0)を使ってカーネルビルド時間を短縮

CentOS 6 のカーネルを若干カスタマイズして、再ビルドして使っている環境があるのですが、ビルド時間を多少短縮したいのと、SSD の消耗を軽減したく、ramdisk を使ってみました。

以下、自分向けのメモですが、どなたかの参考まで。

まず、ビルドに利用しているマシンは、メモリ 16G 積んでます。
カーネルをビルドするには、だいたい 10G は空きディスクが必要なので、ramdisk のサイズを 10G にするため、grub.conf にブートパラメータを追加します。
    ... ramdisk_size=10240000
再起動したら、ramdisk にメモリを割り付けてしまうため、ゼロ埋め処理します。
# shred -z -n 0 /dev/ram0
これは、dd if=/dev/zero of=/dev/ram0 bs=1M としても、いいですが。。

あとは、mkfs してマウントします。
# mkfs -t ext4 /dev/ram0
# mkdir /mnt_ram0
# mount /dev/ram0 /mnt_ram0
そんで、~/rpmbuild の内容を ram0 へコピーします。
# cd ~/rpmbuild
# tar cf - . | (cd /mnt_ram0 ; tar xf -)
最後に、ram0 を ~/rpmbuild へ再マウントします。
# umount /mnt_ram0
# mount /dev/ram0 ~/rpmbuild
これで、カーネル再ビルドの前準備完了です。

実際、やってみたところ、わたしの環境では、ビルド時間が2分程度(全体の処理時間の11%)短縮できました。

ちなみに、最初は zram を使おうとしたのですが、再ビルドしたいのは 32bit 版カーネルであり、ビルド環境も 32bit 版であるため、メモリ限界(ちゃんと調べてないですが、おそらく lowmem の限界)で、うまく行きませんでした。ramdisk のほうは、highmem を使えるようで、問題ありませんでした。

16G メモリって、なかなか使いこなせてない(余りがち)ですが、ちょっとばかり有効活用できたような気もしました。

2014-02-15追記
最初に zram を使おうと思った流れで、ramdisk + ext4 を使いましたが、他に tmpfs もあるので、そちらも試してみました。
CentOS 6 では、デフォルトで /dev/shm に tmpfs がマウントされますが、サイズが少し不足するので拡張します。あと、カーネルビルドの性質上、多数のファイルを作成するので、inode 数も拡張します。
# mount -o remount,size=10240M,nr_inodes=300000 /dev/shm
                        ※64bit版をビルドする場合は足りないようです。12800M なら成功 (2019-03-20追記)
inode 数も拡張しないと、ビルドが失敗します。このとき、容量不足と勘違いしそうなメッセージ(No space left on device)が出て、紛らわしいです。

あとは、次のように bind マウントして利用しました。
# mkdir /dev/shm/rpmbuild
# cd ~/rpmbuild
# tar cf - . | (cd /dev/shm/rpmbuild ; tar xf -)
# mount --bind /dev/shm/rpmbuild ~/rpmbuild
ビルド時間は、ramdisk を利用した場合と変わりませんでしたし、tmpfs を使うほうが手軽かと思います。マシンを再起動しなくても、メモリ解放できますし。
ただ、メモリの空き状況によっては、tmpfs の中身がスワップアウトされることがあるので、その点だけ頭の片隅に置いておいたほうがよいかと。

2014-08-30追記
その後、月1回程度(CentOS 6 の errata カーネルが出る度)のペースで、tmpfs を使う方法を使ってカーネルリビルド(ちなみに HZ=250 設定と nonpae 化)していますが、ビルド時間短縮と SSD 負担軽減に役立っていると思います。先日、うっかり、tmpfs を使わずにビルドしたところ、SSD に負荷がかかり、SSD を見失った(高熱のため?)こともあり、tmpfs 役立つなあ と思いました。

2019-03-20追記
32bit版カスタムカーネルを作るのに tmpfs を使い続けてきて問題ありませんでしたが、64bit版を作る用事があり、やってみたところ tmpfs のサイズ指定 10240M では空き容量不足となり、 12800M 指定したらビルドできました。一般的に64bitオブジェクト(.o や実行バイナリ)は、32bitオブジェクトよりサイズが大きいから、っということなのでしょう。自明と思うので、具体的にサイズ確認まではしませんでしたが。
もしも、この書き込みを見て参考にする人はご注意ください。

2014年2月2日日曜日

CentOS 5 + UEKr2 で Btrfs raid1

CentOS 5 + UEKr2 で ZFS on Linux を使い始めて3ヶ月、安定して使えています。
ただ、UEKr2 なら、別の選択肢として Btrfs も利用できるので、一部のデータの格納に使ってみることにしました。
期待しているのは、透過圧縮機能 (compress-force=lzo) と raid1 です。

# mkfs.btrfs -m raid1 -d raid1 /dev/sd[bc]2
# mount -t btrfs -o compress-force=lzo /dev/sdb2 /mnt_hoge
ネット上に沢山の例がありますが、こんな感じで、mkfs と mount を行います。
Btrfs の raid1 は、構成デバイスのうちの1つだけ (上記の例なら sdb2 または sdc2) を指定すれば mount できるという特徴があります。おもしろいアイデアだと思いますが、md に慣れているわたしには、操作対象が定まらずしっくりこない感じがしました。まあ、慣れの問題かとは思いますが。

ここまでは、いたって簡単です。しかし、起動時に自動マウントしようとしたら、うまく行きませんでした。
UUID=ae4ac311-4ef1-478a-a4eb-15bfa4beedc4  /mnt_hoge  btrfs  defaults,compress-force=lzo  1 1
ext4 等と同じ感覚で fstab に上記のように記載したのですが、起動時に自動マウントされず、次のようなメッセージが出ていました。
device fsid ae4ac311-4ef1-478a-a4eb-15bfa4beedc4 devid 1 transid 431 /dev/sdb2
btrfs: force lzo compression
btrfs: disk space caching is enabled
btrfs: failed to read the system array on sdb2
btrfs: open_ctree failed
しばらく格闘した結果、システム起動時のマウント処理の時点では、sdc2 が Btrfs の構成デバイスと認識されていないためと分かりました。
# btrfs device scan
Scanning for Btrfs filesystems
上記コマンドによるスキャン実施後であれば、mount -a でマウントできたため、そのように判断しました。

fstab に指定されたローカルファイルシステムのマウントは、rc.sysinit で行われるので、rc.sysinit を書き換えて、事前に btrfs device scan を実行するようにしてしまえば良さそうですが、今後の initscripts パッケージのアップデートを考えると、毎度・毎度、書き換えるのも手間だし、忘れそうだし・・・ということで、独自のサービス (my_btrfs) を作成して対処することにしました。
#!/bin/bash
#
# my_btrfs      This shell script takes care of starting btrfs
#               on CentOS 5 + UEKr2
#
# chkconfig: 2345 02 99
# description:  initializing btrfs for my server
#
# config:

### BEGIN INIT INFO
# Provides: my_btrfs
# Required-Start: 
# Required-Stop: 
# Default-Stop: 0 1 2 3 6
# Short-Description: initializing btrfs
# Description:  initializing btrfs
#
### END INIT INFO

#
# Authors: luna2 <blue3waters at gmail dot com>
#
# This file is subject to the GNU General Public License.
# It comes with NO WARRANTY.
#

LOCKFILE=/var/lock/subsys/my_btrfs

case "$1" in
  start)
    modprobe btrfs
    if [ $? -eq 0 ] ; then
        btrfs device scan
        mount -a -t btrfs
        touch $LOCKFILE
    fi
    ;;
  stop)
    rm -f $LOCKFILE
    ;;
  *)
    echo "Usage $0 start | stop "
    ;;
esac
このスクリプトを /etc/init.d/ に配置して、
# ls -l /etc/init.d/my_btrfs 
-rwxr-xr-x 1 root root 816 Feb  2 13:36 /etc/init.d/my_btrfs
# chkconfig --add my_btrfs
# chkconfig my_btrfs on
# chkconfig --list my_btrfs
my_btrfs        0:off   1:off   2:on    3:on    4:on    5:on    6:off
という具合にサービス登録します。くわえて、fstab を次のように修正しました。
UUID=ae4ac311-4ef1-478a-a4eb-15bfa4beedc4  /mnt_hoge  btrfs  defaults,_netdev,compress-force=lzo  1 1
この _netdev を指定すると、rc.sysinit による mount がスキップされます。オンラインマニュアル mount(8) 参照。

これで、システム起動時に Btrfs raid1 領域が自動マウントされるようになりました。次のメッセージは、正常に自動マウントされた際のものです。
Btrfs loaded
device fsid ae4ac311-4ef1-478a-a4eb-15bfa4beedc4 devid 1 transid 452 /dev/sdb2
device fsid ae4ac311-4ef1-478a-a4eb-15bfa4beedc4 devid 2 transid 452 /dev/sdc2
device fsid ae4ac311-4ef1-478a-a4eb-15bfa4beedc4 devid 1 transid 452 /dev/sdb2
btrfs: force lzo compression
btrfs: disk space caching is enabled

なお、initscripts は Oracle Enterprise Linux 5 向けのものに置き換えています・・・
# rpm -qi initscripts
Name        : initscripts                  Relocations: (not relocatable)
Version     : 8.45.44                           Vendor: Oracle America
Release     : 3.0.1.el5                     Build Date: Wed 02 Oct 2013 09:51:05 AM JST
Install Date: Sun 20 Oct 2013 07:35:23 AM JST      Build Host: ca-build56.us.oracle.com
Group       : System Environment/Base       Source RPM: initscripts-8.45.44-3.0.1.el5.src.rpm
Size        : 5508014                          License: GPLv2 and GPLv2+
Signature   : DSA/SHA1, Wed 02 Oct 2013 09:51:16 AM JST, Key ID 66ced3de1e5e0159
URL         : http://git.fedorahosted.org/git/initscripts.git
Summary     : The inittab file and the /etc/init.d scripts.
Description :
The initscripts package contains the basic system scripts used to boot
your CentOS system, change runlevels, and shut the system down
cleanly.  Initscripts also contains the scripts that activate and
deactivate most network interfaces.
# grep -i btrfs /etc/rc.d/rc.sysinit  ※とりたてて、btrfs への配慮はない?のかな・・・
# 

2014-02-12追記
compress-force=lzo の効果について、ちょっと確認してみました。CentOS 6 のシステムイメージを tar で固めたファイルを、展開・削除した場合の比較です(圧縮なし、compress=lzo、compress-force=lzo の3パターン)。
[root@hoge ~]# uname -a
Linux hoge 2.6.39-400.214.1.el5uek #1 SMP Tue Feb 4 17:15:09 PST 2014 x86_64 x86_64 x86_64 GNU/Linux
[root@hoge ~]# cat /etc/redhat-release 
CentOS release 5.9 (Final)
[root@hoge ~]# mount /dev/sdb2 /mnt_sdb2
[root@hoge ~]# cd /mnt_sdb2
[root@hoge mnt_sdb2]# ls -l 
total 10671332
-rw-r--r-- 1 root root 10927441920 Oct 20 22:44 sda6.tar
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdb2             196G  7.8G  180G   5% /mnt_sdb2
[root@hoge mnt_sdb2]# grep btrfs /proc/mounts 
/dev/sdb2 /mnt_sdb2 btrfs rw,relatime,space_cache 0 0
[root@hoge mnt_sdb2]# time tar xf sda6.tar 

real    4m1.898s
user    0m2.548s
sys     0m27.315s
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdb2             196G   29G  160G  15% /mnt_sdb2
[root@hoge mnt_sdb2]# sysctl -w vm.drop_caches=3
vm.drop_caches = 3
[root@hoge mnt_sdb2]# time rm -rf test.restore/

real    0m44.677s
user    0m0.272s
sys     0m16.817s
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdb2             196G  8.0G  180G   5% /mnt_sdb2
[root@hoge mnt_sdb2]# cd
[root@hoge ~]# umount /mnt_sdb2
[root@hoge ~]# mount -o compress=lzo /dev/sdb2 /mnt_sdb2
[root@hoge ~]# cd /mnt_sdb2
[root@hoge mnt_sdb2]# ls -l
total 10671332
-rw-r--r-- 1 root root 10927441920 Oct 20 22:44 sda6.tar
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdb2             196G  7.8G  180G   5% /mnt_sdb2
[root@hoge mnt_sdb2]# grep btrfs /proc/mounts 
/dev/sdb2 /mnt_sdb2 btrfs rw,relatime,compress=lzo,space_cache 0 0
[root@hoge mnt_sdb2]# time tar xf sda6.tar 

real    3m52.773s
user    0m2.652s
sys     0m27.360s
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdb2             196G   24G  164G  13% /mnt_sdb2
[root@hoge mnt_sdb2]# sysctl -w vm.drop_caches=3
vm.drop_caches = 3
[root@hoge mnt_sdb2]# time rm -rf test.restore/

real    0m30.179s
user    0m0.250s
sys     0m15.596s
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdb2             196G  7.8G  180G   5% /mnt_sdb2
[root@hoge mnt_sdb2]# cd
[root@hoge ~]# umount /mnt_sdb2
[root@hoge ~]# mount -o compress-force=lzo /dev/sdb2 /mnt_sdb2
[root@hoge ~]# cd /mnt_sdb2/
[root@hoge mnt_sdb2]# ls -l
total 10671332
-rw-r--r-- 1 root root 10927441920 Oct 20 22:44 sda6.tar
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdb2             196G  7.8G  180G   5% /mnt_sdb2
[root@hoge mnt_sdb2]# grep btrfs /proc/mounts 
/dev/sdb2 /mnt_sdb2 btrfs rw,relatime,compress-force=lzo,space_cache 0 0
[root@hoge mnt_sdb2]# time tar xf sda6.tar 

real    2m21.203s
user    0m2.665s
sys     0m27.380s
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdb2             196G   16G  173G   9% /mnt_sdb2
[root@hoge mnt_sdb2]# sysctl -w vm.drop_caches=3
vm.drop_caches = 3
[root@hoge mnt_sdb2]# time rm -rf test.restore/

real    0m30.308s
user    0m0.285s
sys     0m15.576s
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdb2             196G  7.8G  180G   5% /mnt_sdb2
[root@hoge mnt_sdb2]# cd
[root@hoge ~]# btrfs fi df /mnt_sdb2
Data, RAID1: total=15.00GB, used=3.87GB
System, RAID1: total=64.00MB, used=4.00KB
System: total=4.00MB, used=0.00
Metadata, RAID1: total=4.00GB, used=18.90MB
[root@hoge ~]# btrfs fi show
Label: none  uuid: ae4ac311-4ef1-478a-a4eb-15bfa4beedc4
        Total devices 2 FS bytes used 3.89GB
        devid    2 size 97.66GB used 19.06GB path /dev/sdb2
        devid    1 size 97.66GB used 19.07GB path /dev/sdc2
圧縮処理によりディスクアクセスが減って、処理時間が短縮されることを確認しました。そしてなにより、もちろんディスクが節約され、なかなかナイスです。ただ、安定して利用できるのか未知数であり、重要なデータは格納しないほうがいいのではないかと思います。

2014-02-19追記
片方のディスクを抜いて起動した場合にマウントできるか試してみたら、ダメでした。。。
うーむ、そのレベルだと使うのは不安ですね。圧縮機能にだけ期待して、md RAID1 の上に Btrfs を重ねるかな。。。不良セクタ発生時のセルフヒーリングにも期待したかったのですが。
あるいは、冒険はやめて、やっぱり ZFS 一辺倒にするか。
それにしても、オラクルは Btrfs をサポートすると言ってますが、エンタープライズ向けディストリビューションとしては、少々無理があるように思いました。

2014-03-25追記
同じ tar ファイル(sda6.tar 約10GB)を使って ZFS の性能を測ってみました。下記参照。
3つのOSでZFSの性能を比較

2014-05-20追記
https://wiki.archlinux.org/index.php/Btrfs#Creating_a_new_file_system
によると、ごく最近(2013年12月)、デフォルトのブロックサイズが 16k に変更されており、ほとんど全てのワークロードについて faster であるとのこと、それは耳寄りな話しだと思い、さっそく試してみました。
まず、もう一度 mkfs.btrfs です。
# mkfs.btrfs -n 16k -l 16k -m raid1 -d raid1 /dev/sd[bc]2

WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using

adding device /dev/sdc2 id 2
fs created label (null) on /dev/sdb2
        nodesize 16384 leafsize 16384 sectorsize 4096 size 195.31GB
Btrfs Btrfs v0.19
で、前に実験に使った tar ファイルを用いて、展開・削除性能を計ってみました。ただし、compress-force=lzo の場合のみです。
[root@hoge ~]# uname -r
2.6.39-400.214.5.el5uek
[root@hoge ~]# cd /mnt_sdb2/
[root@hoge mnt_sdb2]# grep btrfs /proc/mounts 
/dev/sdd2 /mnt_sdb2 btrfs rw,relatime,compress-force=lzo,space_cache 0 0
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdd2             196G  7.6G  186G   4% /mnt_sdb2
[root@hoge mnt_sdb2]# ls -l sda6.tar 
-rw-r--r-- 1 root root 10927441920 Oct 20  2013 sda6.tar
[root@hoge mnt_sdb2]# time tar xf sda6.tar 

real    1m43.496s
user    0m2.245s
sys     0m23.133s
[root@hoge mnt_sdb2]# df -h .
Filesystem            Size  Used Avail Use% Mounted on
/dev/sdd2             196G   16G  179G   8% /mnt_sdb2
[root@hoge mnt_sdb2]# sysctl -w vm.drop_caches=3
vm.drop_caches = 3
[root@hoge mnt_sdb2]# time rm -rf test.restore

real    0m15.924s
user    0m0.185s
sys     0m9.921s
わたしの環境では効果が見られ、rm の処理時間が約半分になりました。これは、ありがたい。

2014-05-22追記
RHEL7.0 RC を調べていますが、デフォルトのブロックサイズ(node size と leaf size)は 4k のままでした。

2014-06-26追記
node size と leaf size を確認する方法を書いてなかったので、追記。
# uname -a
Linux hoge 3.10.0-121.el7.x86_64 #1 SMP Tue Apr 8 10:48:19 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux
# btrfs-show-super /dev/sdb2
superblock: bytenr=65536, device=/dev/sdb2
---------------------------------------------------------
csum   0x1f36f324 [match]
bytenr   65536
flags   0x1
magic   _BHRfS_M [match]
fsid   32387714-ab8f-4b84-8648-e99ff10a4082
label   btrfs201405
generation  179
root   83771392
sys_array_size  226
chunk_root_generation 84
root_level  0
chunk_root  21004288
chunk_root_level 0
log_root  0
log_root_transid 0
log_root_level  0
total_bytes  209717346304
bytes_used  4044537856
sectorsize  4096
nodesize  16384
leafsize  16384
stripesize  4096
root_dir  6
num_devices  2
compat_flags  0x0
compat_ro_flags  0x0
incompat_flags  0x29
csum_type  0
csum_size  4
cache_generation 179
uuid_tree_generation 179
dev_item.uuid  d39e3ff2-c899-462d-b60f-94366e424cd0
dev_item.fsid  32387714-ab8f-4b84-8648-e99ff10a4082 [match]
dev_item.type  0
dev_item.total_bytes 104858673152
dev_item.bytes_used 16135487488
dev_item.io_align 4096
dev_item.io_width 4096
dev_item.sector_size 4096
dev_item.devid  1
dev_item.dev_group 0
dev_item.seek_speed 0
dev_item.bandwidth 0
dev_item.generation 0
OracleLinux 5 提供の btrfs-progs には、このコマンドは収録されていません。CentOS6/RHEL6 も未収録(RHEL6.5 は Technology Preview ですけど)。
なお、レッドハットは、RHEL7.0 においては、Btrfs は Technology Preview のようです。最終的に公開された英語版リリースノートに書いてました。レッドハットは良識がありますね。と、思いました。
ですけど Btrfs は、もう一息かなという感触を持ってます。ユーザデータ格納ならば、わたしなら ZFS を選択しますが、ルートVOL(/)として使うには、Btrfs のほうがいいように思ってます。ZFS も、がんばればルートVOLとして使えますが、ZFS 自体のバージョンアップ時や、カーネルバージョンアップの際に気をつけて作業する必要があります。あと、ZFS 0.6.3 では、まだ SELinux と併用すると性能が出ないようです。

2014-07-21追記
手持ちマシンのうちの1台で、ルートVOL(/)を Btrfs RAID1(Plextor SSD M6M 128G x 2)にして CentOS7 を使い始めました。マルチブート環境ですが、Btrfs RAID1 に GRUB2 をインストールしても平気なようです。インストール時は、ext4 で1パーティションにインストールして、btrfs-convert で ext4 から Btrfs に変換して起動できる状態にし、さらに btrfs device add と btrfs balance start -dconvert=raid1 -mconvert=raid1 で、RAID1 化しました。ブロックサイズ 16k 化を忘れてました(mkfs し直さないと変更できません)、それと透過圧縮も利用していません。繰り返しますが、Btrfs は RHEL7.0 では Technology Preview になってますので、留意が必要です。わたしの個人的・実験的利用では、何も不都合はありませんが、大事なデータを置くのはやめたほうが良いだろうと思います。

2014-08-30追記
触れていなかったと思いますが、Btrfs RAID1 にした場合、df がレポートする Size が二倍に見えます。錯覚で広々とした感覚になりますが、これが曲者で、本日、大容量のファイル(バックアップ)を格納しようとして、空き容量の半分しか使えないことを忘れ、無駄な時間を費やしてしまいました。
[root@hoge ~]# uname -a
Linux hoge 3.10.0-123.6.3.el7.x86_64 #1 SMP Wed Aug 6 21:12:36 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
[root@hoge ~]# btrfs fi show --mounted
Label: btrfs201405  uuid: 32387714-ab8f-4b84-8648-e99ff10a4082
 Total devices 2 FS bytes used 54.48GiB
 devid    1 size 97.66GiB used 56.03GiB path /dev/sdb2
 devid    2 size 97.66GiB used 56.01GiB path /dev/sdc2

Btrfs v3.12
[root@hoge ~]# df -h /mnt_temp
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb2       196G  109G   85G  57% /mnt_temp
この Btrfs RAID1 領域は、sdb2 と sdc2 で構成されていて、それぞれ 約97G なのですが、df では Size が 196G に見え、空き(Avail)も 85G に見えています。しかしながら、実際に書き込めるのは、RAID1 を加味すると 85G の半分ということになります。本日は、そのことを忘れて、、、”おっ、まだ 85G も書き込めるのか”っと見誤り、50G を越えるサイズのデータを書き込もうとして、途中で失敗してしまいました。
Btrfs RAID1 を使い始めた当初、ちょっと変わっているが、錯覚で広々な感じで、なかなか good かもと思ってましたが、運用上は気をつけないと余計なトラブルの元になりますね。今になって、実にわかりにくい仕様だと再認識(実体験)したのでした。Btrfs 開発者の方、主義主張(あるいは実装上の都合?)があってのこととは思いますが、考え直してもらえないもんでしょうかね。

■関連記事
CentOS 7.2 で Btrfs RAID1 の df 出力が素直になっていた件
人気ブログランキングへ にほんブログ村 IT技術ブログへ