2008/05/22(木)Linuxでmdadmを使ったソフトウェアRAIDの構築・管理メモ

Linux(Ubuntu 10.04 LTS Server)で mdadm を使用してソフトウェアRAIDを構築・管理する方法について述べます。特に既に稼働中のLinuxにHDDを追加してあとからRAID1を構築する方法を述べます。

続きを読む

2008/05/21(水)ML115 G1/Ubuntu 8.04 LTS Serverセットアップメモ

2008/03/28(金)Subversionの設定メモ

リポジトリ管理にもっぱら Subversion を使っているのですが、管理方法などを細かいことを忘れてしまうので、備忘録メモです。

Apacheの設定

svn のリポジトリを http で管理する場合、Apacheにモジュールを組み込む必要があります。

LoadModule dav_module         libexec/mod_dav.so
LoadModule dav_fs_module      libexec/mod_dav_fs.so
LoadModule dav_svn_module     libexec/mod_dav_svn.so
LoadModule authz_svn_module   libexec/mod_authz_svn.so

svnを動作させたいディレクトリを指定し、次のように記述します。

<Location /repo-dir>
    DAV     svn
    SVNPath /var/www/svndata/repo-dir
</Location>

このとき、/repo-dir/ がsvnリポジトリとして扱われ、/repo-dir/ 以下の管理情報はすべて /var/www/svndata/repo-dir に置かれます。

また /repo-dir/ という実ディレクトリ(www内)が存在すると問題が起こります。

SVNPathで指定したディレクトリに実際にリポジトリを作成します。このリポジトリデータは www 権限で読み書きできる必要があります。

# svnadmin create /var/www/svndata/repo-dir
# chown -R www:www /var/www/svndata/repo-dir

リポジトリのディレクトリ分け

これまでの設定により http://svn.duummy.dom/repo-dir は1つのSubversionリポジトリとして機能します。Subversionによって /repo-dir の仮想的なファイルシステムがすべて作られるようになります。

ずっと勘違いをしていたのですが、あるプログラムを開発するとき、/repo-dir 自体を1つのプログラムソース全体として管理していました。

  • repo-dir/
    • Makefile
    • main.c

しかし、この状況ではブランチといったプロジェクトの分岐が不可能になってしまいます。

これを次のような形で行えば、この中には自由にディレクトリやファイルを作ることができ、コピー等も自在に行えます。

  • repo-dir/
    • prog-current/
      • Makefile
      • main.c
    • prog-stable/
      • Makefile
      • main.c

リポジトリというのは単なる管理単位で、その中のいかなるサブディレクトリでも、そのサブディレクトリ単位でチェックアウトやインポートなどが実効できます。実際、複数のプロジェクトからなる大きな1つのプロジェクトは、このようなディレクトリ分けをうまく使うことで管理されます。

補足

これはリポジトリの概念を解説しただけで、コメントで頂いたとおり下のようにするのが一般的です(必ずしも従う必要はありませんが)。詳しくは参考資料をご覧ください。

  • trunk ……現在開発中のもの
  • branches ……ブランチを納めるディレクトリ
    • branch1
    • branch2
  • tags ……タグをつけてリリース版などをおく場所*1
    • Version 1.xxxx

*1 : 実体はブランチと同じ、ある時点でのディレクトリのコピー

リポジトリの登録とコピー

登録は(通常)手元にあるファイルを import によりリポジトリに登録します。

$ svn import local-dir http://svn.duummy.dom/repo-dir/prog-current

今登録したリポジトリをマスターとして使用しますので、(面倒でも)一度リポジトリから手元のディレクトリにコピーする必要があります。

$ svn checkout http://svn.duummy.dom/repo-dir/prog-current

リポジトリを分岐(ブランチ)させたいときは、同一リポジトリ内でコピーします。

$ svn copy http://svn.duummy.dom/repo-dir/prog-current
           http://svn.duummy.dom/repo-dir/prog-stable

クライアント側の操作

一度チェックアウトしてしまえば、あとは簡単です。チェックアウトしたディレクトリに移動し(prog-current/等)て操作します。

最新のソースに追従
$ svn update
変更箇所をリポジトリに反映
$ svn ci -m "チェックインのメモ"

特定ファイルの変更を破棄
$ svn revert file.c
ファイル/ディレクトリを削除
$ svn delete file.c
ファイル/ディレクトリを追加
$ svn add file.c

差分表示
$ svn diff
リビジョン指定して差分表示(13とローカルのもの)
$ svn diff -r13
リビジョン指定して差分表示(11と12)
$ svn diff -r11:12

作業コピーのブランチ切り替え
$ svn switch http://svn.duummy.dom/repo-dir/prog-stable

参考資料

2008/02/24(日)フラッシュメモリは何日で壊れる? ウェアレベリングの仕組み

一昔前はLinuxマシンにCFディスクをCF→ATAPI変換して使うということもありました。SSDをはじめ半導体不揮発メモリが盛り上がりつつある時代、寿命について考えてみたいと思います。

なお、SSDのいわゆるプチフリーズと呼ばれる現象の正体は、このウェアレベリングに他なりません。*1

資料:SanDiskCF仕様書SanDiskウェアレベリング(ホワイトペーパー)

SanDiskのCFについて考察しますが、他社製の半導体メモリでも同様の機構があります

*1 : このような書き込み中に数秒とまるという現象は、SSD登場以前のCFでも既に起こっていました。

半導体メモリの寿命

ほぼすべての半導体メモリには構造上の寿命があります。これは書き込み回数の制限で、一般的に10万回(多くて30万回)と言われています。しかしこれはSLCタイプと呼ばれるメモリの話で、現在主流となっている安価なMLCタイプ*2では1万回程度と言われています。(この記事では30万回を寿命として計算していますので、普通のSD等では1/30だと読み進めてください。)

30万回ならば到底問題ないじゃないかと思うかも知れません。

しかし、例えば30万回だとして、1秒に1回データを書き込んでいたとすると

3600(秒)×24(時間)=86400
86400×4日=345600

となり、たった4日で壊れる計算になります。同じファイル(の同じ場所)をそんなに書き換えないと思うかも知れませんが、ファイルシステムというものが存在するので、ログディレクトリ内で1秒1回書き込んでいると、常に同じ場所に存在するログディレクトリ(ディレクトリファイル)は1秒に1回書き換えられることになります。*3

デジカメの写真なら30万枚撮らないと壊れませんが、パソコンのディスクとして使用すると結構簡単に壊れることが分かると思います。

*2 : この回数は1セルに2bit以上記録する。

*3 : Windowsは、ファイルに触るたびにファイルへの最終アクセス時刻をファイルシステムに記録するのでもっと酷いことになります。レジストリを操作すればオフにできますが。

SanDisk製コンパクトフラッシュの故障防止機構

SanDisk製CFにはウェアレベリングという故障防止機構が搭載されいてます。

ディスク容量などによって大きさは変化しますが、CFは16KBごとの物理ブロックに分割されて内部管理されています。またディスク全体は4MBごと*4にゾーンとして切り分けています*5。各ゾーンは約3%(128KBぐらい)の余剰領域(通常はアクセスできない)を持っています。

waer_leveling.png

CF内のアドレス(CHS/LBA)はそれぞれ4MBごとに物理ゾーンと対応しています*6。各ゾーンは「Erase Pool」と呼ばれる空き領域の線形リストを持っています。データの書き込まれていないブロックはすべてErase Poolに置かれます

ゾーン内への書き込み命令があったとき、対応する物理アドレスを直接書き換えるのではなく、「Erase Pool」から1ブロックを取り出しそこに内容を書き込み、それを(内部的に)書き込んだ論理アドレスに対応させます。今まで論理アドレスに対応していた物理ブロックは消去した上で「Erase Pool」に移動されます。こうすることでゾーン内での書き込みを分散させます。

しかしこのままでは、各ゾーン(に対応する論理アドレス)に書き込みが集中したときあっという間に壊れてしまいます。そのためゾーンに対する書き込みがある一定数に達すると「対応ゾーンの変更処理」が行われます。ゾーンAとゾーンBのデータが入れ替えです。入れ替えといっても、ディスク内部でデータを互いにコピーしているだけですので少々時間がかかります。実際、CFに対して連続書き込み*7を行うと、一定回数書き込みむごとに動作が2~3秒停止します*8。このときゾーン間のコピーが発生しているようです。

このようなゾーン内の分散処理とゾーン自体の入れ替え処理により、書き込み負荷はディスク全体に分散され、ディスクに空き領域があればあるだけディスクの寿命が伸びます。半導体メモリ各社で実装には色々な違いや特徴(特許)ががりますが、このようなディスクの機構をwear leveling(ウェアレベリング)といいます。

*4 : ディスクによって異なります

*5 : 書き込みや読み込みは、通常ページやセクタ単位(512byte等)で行われますが、消去(空き領域管理)はゾーン単位です

*6 : メモリのページング機構みたいなもの

*7 : 同一ファイルの上書きアップデートとF_SYNC

*8 : SSDで言うところのいわゆるプチフリーズ現象です。

ウェアレベリングの実際

かなり秀逸な機構……に見えますが、実際はそうそう上手く行きません。この機構が正しく働くためには、書き込みを行うディスクに空きゾーン領域がたくさんなければなりません。

例えば、CFディスクを結構使い動作も遅くなってきたので、一度フォーマットして全領域を一度開放したいと思ったとします。ここで、WindowsなどからCFディスクをフォーマットすると(クイックフォーマット除く)どうなるでしょうか? 空き領域(空きブロック/空きゾーン)を増やすつもりが、逆にCFディスクの全領域が使用中にマークされてしまいます。空き領域(空きブロック等)を増やそうとファイルを削除してもまったく増えません。

なぜなら、ディスクはファイルシステムの空き領域を知ることはできないからです*9。ディスク側は1度でも何か書き込まれれば、そのブロックは使用済領域とみなします。

もし、ディスクの空き領域(空きブロック等)を増やすのであれば、ディスクに対してそのブロックが既に使用されてないことを教える特殊なコマンドを発行してあげる必要があります。実際、CFにはそのようなコマンドとして「CF ERASE SECTORS」が規定されています。しかしながらIDEディスク代わりやUSBメモリとして使っている場合、このコマンドは発行されません*10

要するに全く未使用の状況ならともかく、使っているうちに実際のディスク使用率(ファイルシステム上の空き領域)に関わらず「Erase Pool」はどんどん減少していきます。うっかり通常フォーマットやエラーチェックでディスク全体の書き込み検査でもしようものなら、「Erase Pool」は最初から余剰分として用意された3%しか無くなります。

*9 : ディスク自体にファイルシステムの機能があるのではなく、OSがファイルシステムを持っているのだから当たり前です

*10 : OSとデバイスドライバに依存しますが、OSがディスクを普通のHDD等とみなしている限り無理でしょう。ZPOOL(ZFS)なんかだと、ディスクまで開放命令(ERASE SECTORS)が発行されるみたいです。あとここ最近のSATA接続のSSDとかも開放されるらしい。

3%の余剰セクタで何日使える?

例えばディスク容量が2GBとすると、2048MBの3%で62MBの余剰領域となります。16KBの消去ブロックで考えると62MB/16KB=約4000となります。理想通り効率的にディスク全体に書き込みが分散されるとしたら、1秒1回書き込むとして

4000(ブロック数)×300000(寿命)/86400=13653日

となります。書き込み回数が1秒2回(各16KB以内)ならば、この値は半分になるし容量が半分になっても半分になります。

用途によっては秒間10回(または160KB/sec)の書き換えというのは、それほど非現実的ではありません。このときたった136日でCFは壊れます。もちろんこれはウェアレベリングが理想的に動作したときで、実際はもっと前にエラーが起こるでしょう。

CFのエラーマネジメント機構

ちなみにCFには(HDDにも)エラーマネジメント機構として、エラーのあった場所を代替セクタで置き換えるシステムがあります。HDDのエラーは一度起これば広範囲かつ致命的に起こるのですぐに発見できますが、CFのエラーは局所的にしか発生しないため、エラーマネジメントによって置き換えられ隠蔽されます。*11

よってCFのエラーの発生を調べるのはかなり大変です。

*11 : 仕様書には記載されていませんが、この置き換えにはさきほどの3%の余剰ブロックが使われていると思われます。

まとめ

半導体メモリを使用する際は、構造的な有限寿命であることを考慮の上、書き込み回数をよく見積もってから使うべきです。ユーザー環境なら構わないでしょうが、サーバや組み込み系システムで(HDDよりもいいだろうと思って)安易に半導体ディスクを使うと大変なことになります。

今回行った計算はあくまで例です。寿命はセルあたりの書き込み回数寿命、ウェアレベリングの方式、zoneサイズ、全容量が大きく関係しますが、それは製品によって異なります。

2008/02/22(金)UNIXのコンソールメーラー mutt の設定メモ

出先などでメールを確認したいとき、今までは mail コマンドで行っていたのですが、さすがに何百通もあるSPAMの中にまぎれたメールを探すのは大変です。

コンソールメーラーといえば mnews だったのですが、危険なのか今は使われなくなっている様子(FreeBSDのPortsやLinuxのパッケージに存在しない)。

検索しても代わりになるようなメーラーの情報がほとんどみつからず*1、ほとほと困っていたところ mutt というメーラーを教えてもらいました。

*1 : X上のメーラーばかりみつかる

muttの設定(Ver1.5.6系)

日本語版のパッケージをインストールしました(FreeBSDではjapanese/mutt)。特にインストール時に設定する必要はありません。

インストール後、自分は次のように設定ファイル ~/.muttrc を書きました。

# 日本語環境設定(日本語サイト参照)
set send_charset="us-ascii:iso-2022-jp"
set strict_mime=no
set assumed_charset="iso-2022-jp:euc-jp:shift_jis:utf-8"
set thorough_search=yes
set sanitize_ja_chars=yes
set rfc2047_parameters=yes
set edit_headers=yes

# メールアドレスホスト名
set hostname="xxx.yy"
# 送信メールのbccを書かない
set write_bcc=no
# 終了時に、常に mbox 等にメールを移動しない
set move=no
# bccのデフォルトに自分のアドレス
my_hdr Bcc: my-address@xxx.yy

標準動作で /var/mail等(Maildirも対応している) にあるメールをそのまま表示します。終了時に指定しなければ、mboxに移動されることもありません。画面操作は直感的で悩むこともありませんでした。

メールを読むのが楽になり、間違えてメールをmboxに移動することもなくなったため(重要*2)、とても助かりました。

*2 : あとでPCでメールを受信できなくなるので困る

muttの設定(Ver1.5.1x系)

UbuntuのUTF-8環境で、メールタイトルなどが文字化けするなあと思ったのですが、パッチを充ててソースから入れた mutt Ver1.5.6 を使っていたのが原因でした。

それを消した後で、普通に apt-get で Mutt 1.5.17+ が入ったらうまく動きました。

以下、その時のMaildir環境での設定メモ。

# cat /etc/Muttrc
# 日本語環境設定
set send_charset="us-ascii:iso-2022-jp"
set file_charset="iso-2022-jp:euc-jp:shift_jis:utf-8"
set assumed_charset="iso-2022-jp:euc-jp:shift_jis:utf-8"
set thorough_search=yes
set rfc2047_parameters=yes
set edit_headers=yes

# Maildir
set mbox_type=Maildir
set folder=~/Maildir
set spoolfile=+
set tmpdir=+tmp
# 送信メールのbccを書かない
set write_bcc=no
# 終了時に、常に mbox 等にメールを移動しない
set move=no
# メールアドレスホスト名
set hostname="xxx.yyy"

"+"は folder に設定した値が展開されます。

使用Version

# mutt -v
Mutt 1.5.17+20080114 (2008-01-14)
Copyright (C) 1996-2007 Michael R. Elkins and others.
Mutt comes with ABSOLUTELY NO WARRANTY; for details type `mutt -vv'.
Mutt is free software, and you are welcome to redistribute it
under certain conditions; type `mutt -vv' for details.

System: Linux 2.6.24.3 (x86_64)
ncurses: ncurses 5.6.20071124 (compiled with 5.6)
libidn: 1.1 (compiled with 1.1)
hcache backend: GDBM version 1.8.3. 10/15/2002 (built Jun 15 2006 21:27:32)
コンパイル時オプション:
-DOMAIN
+DEBUG
-HOMESPOOL  +USE_SETGID  +USE_DOTLOCK  +DL_STANDALONE
+USE_FCNTL  -USE_FLOCK
+USE_POP  +USE_IMAP  +USE_SMTP  -USE_GSS  -USE_SSL_OPENSSL  +USE_SSL_GNUTLS  +USE_SASL  +HAVE_GETADDRINFO
+HAVE_REGCOMP  -USE_GNU_REGEX
+HAVE_COLOR  +HAVE_START_COLOR  +HAVE_TYPEAHEAD  +HAVE_BKGDSET
+HAVE_CURS_SET  +HAVE_META  +HAVE_RESIZETERM
+CRYPT_BACKEND_CLASSIC_PGP  +CRYPT_BACKEND_CLASSIC_SMIME  -CRYPT_BACKEND_GPGME
-EXACT_ADDRESS  -SUN_ATTACHMENT
+ENABLE_NLS  -LOCALES_HACK  +COMPRESSED  +HAVE_WC_FUNCS  +HAVE_LANGINFO_CODESET  +HAVE_LANGINFO_YESEXPR
+HAVE_ICONV  -ICONV_NONTRANS  +HAVE_LIBIDN  +HAVE_GETSID  +USE_HCACHE
-ISPELL
SENDMAIL="/usr/sbin/sendmail"
MAILPATH="/var/mail"
PKGDATADIR="/usr/share/mutt"
SYSCONFDIR="/etc"
EXECSHELL="/bin/sh"
MIXMASTER="mixmaster"
開発者(本家)に連絡をとるには <mutt-dev@mutt.org> へメールせよ。
バグをレポートするには http://bugs.mutt.org/ を参照のこと。
日本語版のバグレポートおよび連絡は mutt-j-users ML へ。

patch-1.5.13.cd.ifdef.2
patch-1.5.13.cd.purge_message.3.4
patch-1.5.13.nt+ab.xtitles.4
patch-1.5.4.vk.pgp_verbose_mime
patch-1.5.6.dw.maildir-mtime.1
patch-1.5.8.hr.sensible_browser_position.3