2012年1月15日日曜日

fsckの高速化


突然のサーバダウンなどで正常なシャットダウンシーケンスが走らなかった場合、
サーバ起動時にファイルシステムごとにfsckが実行される。
サービス影響が出ている場合、一刻も早く復旧したいのにも関わらず、
fsckに時間がかかり、もどかしい思いをしたことはないだろうか。

補足。正常なshutdownシーケンスが走る場合もfsckが動作することがある。それは設定による。
定期的に実行されるfsckを無効化にまとめているので参照してほしい。


今回はfsckを高速に実行させ、復旧までの時間を短縮させることを目的とする。

ここではファイルシステムはext3、ジャーナリングモードはext3のディフォルトであるorderedを想定している。
モードの説明についてはここを参照してほしい。


fsckの動作を理解しておかなければ高速化手法の検討はできない。
サーバ起動時にファイルシステムがマウントされるまでの動作を簡単におさらいしておく。


サーバ起動時にファイルシステムがマウントされるまでの動作

ファイルシステムがマウントされるまでにどういった処理と判断がされるか順を追っていく。

(1) ファイルシステムの状態(クリーンフラグの有無)の確認

    (1-a) ファイルシステムの状態がクリーン(clean)である場合
     ⇒ ファイルシステムはすぐにマウントされる。終了。

    (1-b) ファイルシステムがクリーンではない(not clean)である場合
    ⇒ (2)以降の処理が走る。

クリーンフラグはファイルシステム単位で設定されている。
クリーンフラグはファイルシステムのスーパーブロック(ファイルシステムの構成に関する
情報が格納されているブロック)に存在している。

クリーンフラグがセットされていない場合にのみファイルシステムの修復が行われる。

手動で状態を確認することもできる。
既にマウントされている領域であれば当然cleanになっているだろう。
$ su- 
# tune2fs -l /dev/sda1
Filesystem state:         clean

シャットダウンシーケンスが走らずに終了した場合などは、状態がnot cleanとなっている。


(2) ジャーナルによるリカバリ(ジャーナリングを利用している場合のみ)
fsckがファイルシステムのチェックと修復前の前にジャーナルを確認する。

    (2-a) ジャーナルで修復が終わった場合
     ⇒ ファイルシステムはマウントされる。終了。

    (2-b) ジャーナルで修復が完了しなかった場合
     ⇒ (3)の処理(fsckによるPhase1からPhase5までの全ての処理)が実行される。

ジャーナルの説明はここを参照してほしい。
抜粋
『不正なシャットダウン時にfsckコマンドを実行する必要があるのは、
メタデータの整合性が保たれていない可能性があるからだ。
もし不正なシャットダウン時においてもメタデータの不正がないということが保証できれば、
fsckコマンドを実行する必要はない。そもそもファイルシステム全体に対するメタデータの
整合性のチェックをするのは無駄であり、不正なシャットダウン時には、
壊れた可能性のある部分だけをチェックすればよいのではないだろうか。
ジャーナリング内に何か残っていれば、ディスクへの書き込みに失敗した可能性が
あるということがわかる。このときジャーナリング内に記載された手順内容を見れば、
どのような操作をしたかがわかるから、壊れた可能性がある箇所がわかる。
よってその箇所だけを調査すればよい。
すなわち強制的に全メタデータを調査するfsckコマンドによるものと違い、
壊れた可能性がある箇所だけを調べることで、不正なシャットダウン後の
ディスクチェックの時間を高速化することができるというわけだ。』


(3) fsckによるファイルシステムのチェックと修復
fsckによるPhase1からPhase5までのファイルシステム全体に対するメタデータの
整合性のチェックがなされる。
ここまでくると復旧までに時間がかかることは覚悟しなければならない。

・ Phase1(Check Blocks and Sizes)
  ブロックとサイズのチェックを行う。
ファイルシステムはファイルシステム全体をブロックグループに分けて管理するが、
そのブロックのサイズのチェックと、ブロックグループ0(先頭)にある
iノードのチェックを行う。

・ Phase2(Check Path names)
Phase1で見つかった不良iノードのチェックを行い、削除を実施する。

・ Phase3(Check Connectivity)
参照されないディレクトリがないか等、ディレクトリの構成のチェックを行う。

・ Phase4(Check Reference Counts)
参照されないファイルのチェック等、ファイルの参照チェックを行う。

・ Phase5(Check Cyl groups)
シリンダグループからi-nodeもしくはブロック構成のチェックを行う。

以上を踏まえどうすればfsckにかかる時間を短縮できるか考えてみる。



高速化の検討

サーバ起動時にファイルシステムがマウントされるまでの動作を(1)から(3)まで見てもらった。
(1)では何もできることはないだろう。

(2)でできることは、ジャーナリングのカスタマイズぐらいだろうか。
ただし、ジャーナリングが利用できる場合は復旧までにそれほで時間はかからないだろう。

(3)はどうだろうか。
この処理をしなければならないかどうかはもう運しだいなのだが、
やらざるを得ない最悪の事態を想定し、何かしらのアクションをとりたい。

例えばファイルシステムが10個あり、それぞれが数百GBもあったらどれほど時間がかかるだろうか。
想像するだけで恐ろしくなる。
仮に一つのファイルシステムのfsckが1時間かかれば合計で10時間である。

だからといって、fsck自体を簡略化することはコードを見直さない限り不可能である。
であるならば待つしかないだろうか。

シーケンシャルに動作するfsckを並列に動かせばいいのではないだろうか。

先ほどの10個のファイルシステムがある場合、システムが動作させる1つのfsckの裏で、
手動で同時に別領域をfsckできれば短縮できるはずである。
サーバの負荷をモニタしつつ何多重まで動かせるか決定すればよい。

手動でfsckが完了した領域をシステムもその後に2重でfsckかけるだろうが、
ファイルシステムの状態はすでにcleanになっているので即終了である。

ただしこれを実施するには、システムがクラスタを利用しており、
フェールオーバ先にログインできる、という条件が必要になるだろう。

スマートな手段を期待してここまで目を通してもらった方には申し訳ないが、
これが現実的に効果があり、かつ容易にできる方法ではないだろうか。


FSCK備忘録
Q. fsckが走っている領域を2重でFSCKかけた場合どうなるか?
A. 2重には実行できない。
システムがfsckしている箇所を手動で実行してしまうことを心配する必要はない。