最終更新:
メモ無し&焦り&かなりうろ覚え&再現できない内容なので、信頼性に欠けています。
ゴールデンウィークに電源設備のメンテナンスで停電になるので、サーバを含めた全ての機械の電源を落とすことになった。てなわけで予定時間にサーバの電源を落とす役に。
予定時間になったのでサーバの電源スイッチを片っ端からホイホイ、ホイッと押していった。全て電源ボタンでシャットダウンできる。ついでにUPSもメンテナンスしたかったので、しばらくしてからUPSの電源スイッチを切った。
パチン カチッ ・・・ あれっ?
何だ?今の音?「パチン」はUPSのスイッチの音。じゃ「カチッ」は?・・・第2サーバ?!。もしかして・・・
電源入ってた?(汗)
ディスプレイが別のサーバに切り替わっていた(か、ディスプレイの電源を切ってあった)ので気がつかなかった・・・。・・・とりあえず・・・電源を入れなおしてみる。OSの起動は・・・OK。いや、ファイルシステムの初期チェックでやっぱり同期が取れていない(書き込みキャッシュが正常に書き込まれていないような感じ?)らしい。とりあえず起動はできて、バックグラウンドでファイルシステムのチェックをしているようだ。まぁ、アクセスも無い時間だし作業中というわけでもなかったから様子を見てみるか。
と、思っていたら、
カーネルがパニックしました。何かキーを押すと再起動します。
(の、ようなことが実際には英語で表示)
Σ<(゙ロ゙;)> (脂汗)
とりあえず・・・頭の中には再起動しかなかった。前回と同じようにファイルシステムの初期チェックで引っかかって、バックグラウンドでファイルシステムのチェックをしている。とりあえず原因を調べないと。
と思っていたらまたパニックが。今度はタイピング中だったのでメッセージの確認も出来ずに再起動してしまった。その後も同じようにパニックが出た。
最初パニックになった時はちょうどUSBキーボードを切り替えた時点だったので、USBのプログラム関係だと疑っていたのだが、最終的にはメッセージに自作のプログラムの名前が載っていたので、たぶんそれだろうと思った。
自作プログラムは図面データディレクトリを探索してファイル名や図面情報を収集するためのもの。crontabに登録し、数分間隔で自動実行していた。
このままではまたパニックになって再起動する羽目になるので、そのプログラムの自動実行を止めた。・・・その後パニックにならなくなったので、どうやらビンゴだったらしい。
とりあえずファイルシステムがどのくらいダメージを受けたのかわからないので、ファイルチェックをしようと・・・はて、どうやってやるんだっけ?。fsckだったかな?。おっと、バックグラウンドのチェックが終わってからのほうがよさそうだな。
% fsck
自動的に全てのマウントポイントの検査が行われているようなのだが、なんかやたらと不整合が見つかっているのにも関わらず、修正しない&修正するかどうかの確認もなく終わってしまった。システムが使用しているファイルシステムだからかなぁ?そうだったらいいんだけど。
とにかく休み明けまでにはどうにかしたいので、ブートCDから立ち上げ、sysinstall
のFIXITからシェルを呼び出す。
# fsck /dev/ad1s0a
デバイスを指定してfsckを使ってみる・・・が、なんやかんややってみてもfsck_ufsが見つからないとエラーになってしまう。しかもこのキーボード、デフォルトではアンダーバーが押せない(泣)ので、直接実行する術がない。
CDブートからはあきらめて、HDD起動のシングルユーザモード(Windowsのセーフモードみたいなもんかしら?)でやってみる。起動画面でSingle user modeを選ぶ。シェルを聞かれるのでとりあえず/bin/shでいいや。
シェルになったところで同じようにやってみた。
# fsck /dev/ad0s0a
ん、できた。できたのはいいけど、不整合とかは無いらしい。ルートファイルシステムだからマウントしているはずだけど・・・まぁ、問題ないならいいか。
続けて他のパーティーションも同じようにやってみた。すると、ほとんどのパーティーションに不整合が見つかった。一見、修正しても良さそうな感じだが、英語で内容がはっきりわからない(泣)ので、念のため調査してからにしよう。
気がついたら・・・もうすぐ21時・・・。もう時間切れになってしまったので、一旦家に帰って調査&対策を練ってから、休み明けの業務開始前になんとかしよう。
ゴールデンウィーク中にfsckとそのメッセージについて調べてきた。
とりあえず電源を入れ、HDDからシングルユーザモードで起動する。やっぱりシステムがアクティブにしているデバイスでは使用中の領域がどうしてもあるため、その部分の検査は誤検知するということだった。ハードディスクの全てのパーティーションにfsck
を実行してみると、結局「(使っていない領域があるため)ディスクの使用量が食い違っている」というメッセージが出たらしい・・・たぶん(おい)。そんなわけでyで修正。
なんとか業務開始までに再チェックも済ませて、改めて再起動までこぎつけた。その後は特に問題は発生していないようだ。ふぅ。
/varが修正されているので、なにかログファイルにデータ的な損傷が出ているかもしれないと思い、調べてみた。が、とくにログファイル自体が壊れているような感じは無かった。が、最初にfsckでバックグラウンドチェックしている時の状況がシステムログに残っていた!。
「どこそこのinodeのファイルサイズがおかしい」とかいうメッセージが大量に残っていた。でもどのファイルなんだろう?。
ん?inodeといえばfind
コマンドの条件にそんなのなかったか?。マニュアルを調べてみたら、やっぱりあった!。これを使ってどのファイルがダメージを受けたか調べてみる。
% find / -inum inode
結局、壊れたらしいファイルは、カーネルパニックを引き起こした自作プログラムが書き出した一時ファイルと、entropy.?ファイル・・・。調べてみたらなんか、いらなそうだな。というわけで、再起動より古い日付のものはサクッと削除。自作プログラムの一時ファイルも当然サクッと削除。
例のカーネルパニックを引き起こすプログラムがそのままだった。このファイル自体は通常書き換えしないので、たぶん壊れた一時ファイルにアクセスできなくてパニックを引き起こしたと思うのだが・・・。念のためコンパイルし直した。
恐る恐る自作プログラムで一時ファイルを作る動作をしてみた。
・・・・・OK!、カモ〜ン。大丈夫だった。
その後は何事も無かったように動いている。良かったぁ〜。なんか「朝、サーバに繋がらなかった」というクレームがあったが適当に涼しい顔で「すんません電源入れるの遅くなりました」みたいな返事をしておいた。だって本当の事言ったらそれこそパニックになるんじゃ?
会社の先輩とapache&.htaccessによるアクセス制御の話をしていてmod_rewrite
なるものが出てきた。そーいえば見かけたよーな、という感じだったが、調査してみるとなかなか面白い動きを見せてくれそうだ。てなわけで・・・。
apache2はスタティックリンクでコンパイルしてあったのと、(現業のほうが忙しく1人で残業中だったので)、どうせならと思い、apacheの最新版2.0.63(当然、当時の最新だが)のソースを拾ってきた。コンパイルスクリプトも手直ししてコンパイル。見ていなかったが小一時間程度でmakeまで終わったようだ。神に祈りつつインストール。
% /usr/local/apache2/bin/apachectl stop % make install % /usr/local/apache2/bin/apachectl start
apache2を起動しようとしたらモジュールが見つからないと蹴られた。そっか、DSOだもんな。httpd.confを試行錯誤して手直しする。使わないつもりだったモジュールが、実はhttpd.confで使っていたということだ。全部DSOでも良かったかな?
httpd.confの訂正だけで実運用もクリアした。
何もトラブルなく動いているようだ。Webサーバのアップデートなんて会社で知っているのは俺ぐらい・・・。
番外:仮想サーバにてPHP5リベンジにて仮想サーバでPHP5が動くことを確認したので、実機インストールに再チャレンジしてみようと思う。明日は休日出勤だし。(ていうかこのインストール記録も時間軸飛びまくってるなぁ・・・(汗))
今日は休日出勤。しかも・・・他に誰もいない(汗)。これは神様が俺に「サーバを止めるなら今ですよ」と言ってくれているに違いない(笑)。じゃ遠慮なく
% sudo sh /root/php526.build.sh
現業を頑張っていたらいつのまにかコンパイルが終わっていたので
% /usr/local/apache2/bin/apachectl stop % cd /usr/src/php5.2.6 % make install httpd.confでPHP4をコメントアウト % /usr/local/apache2/bin/apachectl start
お、ちゃんと起動してるじゃん。phpinfo()
もちゃんと5.2.6になってるね。
テスト版プログラムを動かしてみたら・・・表示された。よしよし。じゃあこっちのプログラムは?・・・おや?反応が遅い。結局タイムアウトになってしまった。じゃあこっちは・・・文字化け。おいおい、文字化け対策は直ったんじゃなかったのか?。
文字化けが発生したので、文字化けしないためのルーチンを調べてみた。すると、以外や以外、mb_convert_variables()
関数で止まっちゃう!(=ハングアップというか)。また訳の分からないパターンか・・・(泣)。結局、PHP4に戻した。
とりあえず実機だとコンパイルもそんなに時間がかからないし、インストールも見ていられるぐらいの時間で済むので、いろいろなパターンで試してみた。
PHP5.2.6→×、PHP5.1.6→×・・・。PHP5系はなんでダメなんだろう?。というか、仮想サーバでは同じようにやっても問題なかったのになぁ・・・。
とりあえず言えることは、リクエストが発生してからタイムアウトするまでCPUの使用率が100%近くになること、正常にタイムアウトになるよう監視は出来ているということ。
調べてみたところ、PHP4とPHP5とで共存できる設定があるということで、実践してみる。おお、とりあえずphpinfo()
でそれぞれのバージョンが表示された。スゴイ。
あれ?共存できていたはずなのに、いつの間にかPHP5のphpinfo()
でServer Errorが出るようになってしまった。何を変えたらおかしくなったのかもうわからない。apache2のログにはPremature end of script headers等が書かれているだけで手がかりは薄い。
SuEXEC
をやめたり/cgi-bin/にScriptAlias
してあるディレクトリを確認してみたりしたが、一向に直らない。困った。ちなみにPHP4は全く問題ない。
PHP5の不具合が原因でPHP4とPHP5の共存がうまくいかないのでは?と疑っていたのだが、念のためapache2の設定を最初の状態に戻してみた。
--prefix=/usr/local/php5
--enable-force-cgi-redirect
--with-config-file-path=/usr/local/php5/etc
(--with-apxsや--with-apxs2は必ず外すこと)
ScriptAlias /cgi-bin/ /usr/local/php5/bin/
<Directory /usr/local/php5/bin/>
AllowOverride None
Options None
Order allow,deny
Allow from 192.168
</Directory>
AddHandler php5-script .php
Action php5-script /cgi-bin/php-cgi
なんだったんだろう?.htaccessに入れたのが良かったのかと思ったが、行の順番を入れ替えたらおかしくなったので、記述の順番に問題があったようだ。とはいえ、そんなのマニュアルのどこに書いてあったんだろう?。ちなみに今回の例はかなり適当な部分もあるので丸写しは注意。
それでもやっぱりphpinfo()
は動かなかった。コンパイラオプションもいろいろ変えて、終いにはオプション無しでやっても同じだった。
コンパイラオプションがダメならconfigureオプションかと思い、とりあえずマルチバイト関連とMySQL関連のオプションを外した。
あ?、動いた。じゃあMySQL関連を組み込んで・・・。
あ?、動いた。じゃあ--enable-zend-multibyte
だけ足して・・・。
あ?、動いた。じゃあ--enable-mbregex
だけ足して・・・。
動いた・・・。ということは、--enable-mbstring
が元凶か・・・。
待てよ?、前にmb_convert_variables()
で止まったことがあったな・・・。
;mbstring.http_input = auto(コメントアウト)
php.iniを変更した後、--enable-mbstring
も足してコンパイル。
動いた・・・orz
とりあえず頭の中を整理してみよう。
phpinfo()
と、文字化けはしたものの一部のプログラムもなんとか動いていたはず。mb_convert_variables()
である。;mbstring.http_input = auto
をコメントアウトしただけの状態にしたらphpinfo()
が動くようになった。$_POST
等のスーパーグローバル変数をmb_convert_variables()
で変換するとタイムアウトしていたので、mb_convert_encoding()
等を使った自前の関数で変換してみたら、文字化けも解消された。mb_convert_variables()
が原因かと思いきや、後に再現してみようと思っても現象が発生しなかった・・・なんなんだ?。・・・・・・謎は深まるばかり。
いや、どこか勘違いしているかもしれない。もう一度試してみよう。
mbstring.language = Japanese
mbstring.internal_encoding = EUC-JP
mbstring.script_encoding = auto
mbstring.detect_order = auto
mbstring.http_input = auto
mbstring.http_output = SJIS
mbstring.encoding_translation = On
mbstring.func_overload = 0
mbstring.strict_detection = On
;mbstring.substitute_character = none
mbstring.http_input = auto
を有効にしてみる。<?php phpinfo(); ?>
をphpinfo.phpというファイルで用意する。mbstring.http_input = pass
に変更してみる。mb_convert_variables(mb_internal_encoding(), 'auto', $_GET);
を追加してみる。mb_convert_variables()
。mb_convert_variables()
行を$a = array('a' => 'はにほへといろは');
mb_convert_variables(mb_internal_encoding(), 'auto', $a);
に変更してみる。ただしスクリプトはSJISで、スクリプトの自動変換が有効になっている。$a = array(
...行を$a = array('a' => mb_convert_encoding('はにほへといろは', 'SJIS'));
に変更してみる。mb_convert_variables()
。$a = array(
...行を$a = array('a' => mb_convert_encoding('はにほへといろは', 'UTF-8'));
に変更してみる。mb_convert_variables()
関数を、自前の関数に変更してみる。ただし自前の関数ではmb_convert_encoding()
を使用している。$a = array(
...行を$a = array('a' => mb_convert_encoding('はにほへといろは', 'SJIS'));
に戻してみる。$a = array(
...行をやめて、$_GET
を自前の関数で変換するように変更してみる。明日は7月7日、環境省が「夜電気を消せ」と言っている日。うちの会社でもエコ活動を始めた&自分もその推進メンバーに入ってしまっているので、サーバの24時間稼動も見直さなければと思っていた。
シャットダウンさせるのは/etc/crontabにshutdown -p now
を指定してやればOKなのだが、停止時間中にperiodic daily
とかあるのよね。
えいっ!って発動時刻を変更してみた。
次の日早く出社。問題ないようだ。おけおけ。今のうちにサーバを再起動してBIOS設定で自動起動時刻を設定しておく。コレ大事。やっとかないといつまでたっても起動しない。(そりゃ当たり前だ)
終了する前にやっておきたいこと(ログのローテーションとか)をgoodnight.shとかにしてスクリプト化しておく。もちろん最後にはshutdown -p now
を記述しておく。んで/etc/crontabにて終了時刻にそのスクリプトを呼び出すように設定。
当然、社内にアナウンス。今日はクールアースデーだからっつって。
次の朝、またも早く会社に出てきてサーバを確認。うん、起動しているね。おけおけ。