広告:ページ内にてアフィリエイト広告を利用しています。
トラブル

セマフォ不足でApacheが起動できないときの対応方法と対策

ある日、ウェブサーバーが落ちていてサイトにアクセスできなかったため、まずはApacheの再起動を試みましたが実行できず。 このときに実施した対応と今後同じ問題が起きないように対策した内容を記しておきます。

事象と実施したこと

まずApacheの再起動を試みました。
 [admin@hogehoge ~] sudo service httpd restart
実施するも前述通り、立ち上がらず。エラーログを確認します。
 [admin@hogehoge ~] vi /var/log/httpd/error_log

 [Wed Feb 14 08:58:53 2024] [error] (28)No space left on device: Cannot create SSLMutex
すると「(28)No space left on device: Cannot create SSL Mutex」のエラーが確認できます。
こちらはセマフォを使い切ったときに出るエラーです。
セマフォの状況は「ipcs -s」で確認できます。
 [admin@hogehoge ~] sudo ipcs -s

 ------ Semaphore Arrays --------
 key        semid      owner      perms      nsems     
 0x00000000 0          root       600        1         
 0x00000000 32769      root       600        1         
 0x00000000 671449090  apache     600        1         
 0x00000000 671481859  apache     600        1         
 0x00000000 671514628  apache     600        1         
 0x00000000 672333829  apache     600        1         
 0x00000000 672366598  apache     600        1         
 0x00000000 672399367  apache     600        1         
 0x00000000 674791432  apache     600        1         
 0x00000000 674824201  apache     600        1         
 0x00000000 674856970  apache     600        1    
セマフォとは
セマフォは、ある資源が何個使用可能かを示す記録と考えればわかりやすく、それにその資源を使用する際や解放する際にその記録を「安全に」(すなわち競合状態となることなく)書き換え、必要に応じて資源が使用可能になるまで待つ操作が結びついている。セマフォは競合状態を防ぐ便利なツールであるが、セマフォを使うことでプログラムにおける競合状態がなくなると保証するものではない。

wikipediaより
つまり、セマフォは、プログラムの並行処理を制御するための同期手法で、共有リソースへのアクセスを管理します。

こちらがいっぱいになり起動できなくなっている現象です。 現在セマフォの最大値がいくつに設定されているかは以下コマンドで確認できます
 [admin@hogehoge ~] sudo /sbin/sysctl -a | grep sem

  kernel.sem = 250  32000   32  128  (最大値は128)
Apacheが起動できない状態で、apacheのセマフォが溜まっているときは以下のコマンドでクリア可能です。
 [root@hogehoge ~] ipcs -s | grep apache | awk ' { print $2 } ' | xargs ipcrm sem

対策

めったにセマフォが溢れることはないのですが、今後起きたときのためにシェルスクリプトで監視するようにしました。 以下コマンド実行時、現在のセマフォ利用数をチェックして、しきい値を超えていたらセマフォのクリアを実施。Apacheの状態を確認して起動してなかったら再起動するようにしています。
 #!/bin/bash

 SEMAPHORE_NAME="apache"

 THRESHOLD=100

 SEMAPHORE_COUNT=$(ipcs -s | grep "$SEMAPHORE_NAME" | wc -l)

 send_mail() {
    local subject="Semaphore Count Alert"
    local recipient="admin@example.jp"
    local body="Semaphore count exceeds the threshold. Current count: $1"

    echo "$body" | mail -s "$subject" "$recipient"
 }

 if [ "$SEMAPHORE_COUNT" -gt "$THRESHOLD" ]; then
  echo "Semaphore count exeeds the threshold."
  echo "Clearing semaphores..."
  ipcs -s | grep "$SEMAPHORE_NAME" | awk '{print $2}' | xargs -r ipcrm sem
  echo "Semaphores cleared."

  APACHE_STATUS=$(service httpd status)

  send_mail "$SEMAPHORE_COUNT"

  if [[ $APACHE_STATUS != *"running..."* ]]; then
     echo "Apache is not running"
     service httpd restart
  else
     echo "Apache is already running."
  fi

 fi
こちらはセマフォを監視するユーザーを指定します。
  
 SEMAPHORE_NAME="apache"
こちらはセマフォの数が何個以上になったらセマフォを消すかのしきい値を指定します。
  
 THRESHOLD=100
セマフォクリア時、メール通知をするアドレスを指定します。適宜置き換えてください。
  
 local recipient="admin@example.jp"
※メールは送らなくて良い場合は「send_mail “$SEMAPHORE_COUNT”」を削除してください。