セマフォ不足でApacheが起動できないときセマフォをまとめて削除する
まとめ
Apacheが起動できない状態で、解放されず残っているapache
ユーザのセマフォを消すには、rootユーザで
ipcs -s | awk '/apache/{print $2}' | xargs -r ipcrm sem
(/apache/
のところは、Apache実行ユーザに読み替えよう)
経緯
セマフォ不足でApacheが起動できなくなるっていうトラブルがありました。
前回は10か月前19時30分開始のGotanda.pm #3に参加するため19時退社して(うちは定時21時なんです)モバイルファクトリーの社内で参加中20時ぐらいに会社から電話かかってきて「Apacheが起動できませ~ん」というのでリモートで潜って対応。
今回は、アパートの立ち入り検査があるとかで有給休暇を取って全裸待機していたら朝10時位に電話がかかってきて(うちは始業は10時なんです)「Apacheが起動できませ~ん」というのでリモートで潜って対応。
セマフォ不足であることを示す直接のログは出てこず、Apacheのエラーログに
No space left on device: Cannot create SSLMutex
No space left on device: Couldn't create accept lock
No space left on device: mod_rewrite: could not create rewrite_log_lock
等のなんかのスペースが足りん的なエラーメッセージとして出てくるようです(監視システムなどに設定するのはこのエラーメッセージを設定することになる)。
初回のインシデントの時点で自動で復旧できるぐらい組んどけよっていう批判は甘んじて受けますがともかくセマフォ不足でApacheが起動できないというのをGoogle検索しますと、セマフォの消し方としてこういうのが出てきます。
ipcs -s | grep apache | perl -e 'while (>STDIN<) { @a=split(/\s+/); print `ipcrm sem $a[1]`}'
(ダイヤモンド演算子ってそういう書き方できるんだ)よく見るとPerlのワンライナーってwhileを書かなくても書いたことにできるスイッチあったよなーと思ったのでいじってみました。
改善
ipcs -s
で出てくるのは
# ipcs -s ------ セマフォ配列 -------- キー semid 所有者 権限 nsems 0x00000000 0 root 600 1 0x00000000 32769 root 600 1 0x00000000 6619138 apache 600 1 0x00000000 6651907 apache 600 1 0x00000000 6684676 apache 600 1 0x00000000 6717445 apache 600 1 0x00000000 6750214 apache 600 1 0x00000000 3670033 root 600 1
という文字列です。Apacheがセマフォ不足で立ち上がらないというのは、何らかの原因でApacheが作ったセマフォが百数十個残ったままになっているということ。何も考えずCentOS5/6をセットアップすればカーネルに設定されたデフォルト上限値として128個まで作れることになる(see: kernel.sem)。というわけで、セマフォ不足でApacheが起動できないという場合は、apacheの実行ユーザが所有者となっているセマフォをipcrm sem {semid}
を実行して120回ぐらい延々と消す必要がある。
要はipcs -s
をapacheユーザでgrepしたやつの2番目のカラムの{semid}
を引数にしたipcrm sem
を実行させればよいわけなんで、
基本形の
ipcs -s | grep apache | perl -e 'while (>STDIN<) { @a=split(/\s+/); print `ipcrm sem $a[1]`}'
から、
つうことで、
ipcs -s | grep apache | perl -nlE 'split(/\s+/); system "ipcrm sem $_[1]"'
としてみた。よく見ると、Perlのコマンドラインオプションの-a
をつけるとawk
モードになって@F
に自動的にカラムが入ってくれるからsplit
いらなくなるじゃないかと思って、
ipcs -s | grep apache | perl -a -nlE 'system "ipcrm sem $F[1]"'
としてみた。ところで、最近のLinuxディストリビューションだと最小構成インストールでPerlが入らないという大変なことになっていたりするので、Perl抜きで組み立てたほうがよくね?と思い、
ipcs -s | grep apache | awk '{print $2}' | xargs -l -r ipcrm sem
ここまで来ると、grepの作業ってawkでもできるよねってなって、
ipcs -s | awk '/apache/{print $2}' | xargs -l -r ipcrm sem
となる。そんで、よく考えると、ipcrm
のman
を見ていなかったことに気づき、参照したれば、
IPCRM(1) Linux Programmer’s Manual IPCRM(1)
NAME
ipcrm - remove a message queue, semaphore set or shared memory id
SYNOPSIS
ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ] ...
deprecated usage
ipcrm {shm|msg|sem} id...
とありましたので、今まで安全のために入れておいたxargs
の-l
オプション(引数を1個だけにして、1回ずつ実行させる)を取っ払って、
ipcs -s | awk '/apache/{print $2}' | xargs -r ipcrm sem
あたりに落ち着きました。
アイキャッチ画像に使ったセマフォ写真は File:Udegishiki Tokushima.jpg - Wikimedia Commons