2022/06/17(金)OOM Killerでサーバが死んだ

ある日突然、Webサーバ(Apache)が死亡したときのメモと、実施した対策のまとめ。

OOM Killerとは

メモリが足りなくなったときに、負荷が高そうなプロセスを一撃必殺してくれるLinuxの機能です。

ログ

長いので別ファイルに

この中で、rssが実消費メモリ(KB)なのですが、トータルしても209MBしかありません。ps auxの値(KB)と異なり、OOM Killerプロセス一覧数値はすべてページ単位(4kB単位)なので、836MB。このマシンの実メモリ1GBなのでほとんど無くなっています。

スワップもswapents(Anonymous swap entries)の合計が960589、エントリー1つあたり4KBですので、3.7GB。つまりスワップは完全に食いつぶしてる。

色々調べると、OOM発動時はこの辺を見ると良いらしい。

[7934037.757829] Node 0 DMA: 43*4kB (UME) 14*8kB (UME) 12*16kB (UE) 13*32kB (UME) 2*64kB (UE) 7*128kB (UME) 4*256kB (UME) 3*512kB (UME) 0*1024kB 0*2048kB 0*4096kB = 4476kB
[7934037.762116] Node 0 DMA32: 258*4kB (UME) 252*8kB (UME) 576*16kB (UME) 325*32kB (UME) 105*64kB (UME) 20*128kB (UME) 8*256kB (UE) 3*512kB (UME) 5*1024kB (UME) 0*2048kB 1*4096kB (M) = 44744kB

どれくらいのサイズの連続したメモリをいくつ確保できるかという表示ですが、一番大きいもので「DMA側が512kBを3つ」「DMA32側が4096kBを1つ」ということで、メモリの断片化してますし、そもそも両方合わせて48MBぐらいしか空きメモリがない。

OOM Killerが発生して当然の状況と言えます。

なぜApacheが死んだのか

OOM Killerが発動したのは、sys.fcgiというFastCGI(Apacheの子)プロセスなのですが、なぜかApache自体が死亡しておりました。daemon.logを見ますと、こんな感じ。

systemd[1]: apache2.service: A process of this unit has been killed by the OOM killer.
systemd[1]: apache2.service: Failed with result 'oom-kill'.
systemd[1]: apache2.service: Consumed 1h 21min 18.835s CPU time.

Apacheの子プロセスがOOM Killerされたので、systemdが善きに計らってApache自体を終了させた模様。……やめてくれー(苦笑)

子プロセスが死んでもApacheを生かす

メモリ食いつぶしcgiを作って実験してみたのですが、通常のcgiなら問題なくFastCGIのときだけこの問題が起きるようです。systemdの設定を変更して、Apacheを巻き添えにしないよう変更します。

# Debianの場合, rootでの作業
cd /etc/systemd/system
mkdir apache2.service.d
vi apache2.service.d/oom.conf
systemctl daemon-reload

# oom.confの中身
[Service]
OOMPolicy=continue

/etc/system/systemd/apache2.service.d/oom.conf がきちんと読み込まれてるか、設定を確認してください。

systemctl cat apache2

この状態でメモリ食いつぶしfcgiを実行してみましたが、無事(?)にfcgiだけプロセスkillされました。

その他の対策

  • Swap領域を3.7GBから10GBに増強。
  • sys.fcgiで不要になったメモリを開放することが難しかったので、メモリ使用量(/proc/[pid]/statusのVmHWM)が一定量を超えたら、処理終了後に自動でプロセスを終了するようにした。
  • mod_fcgidの設定を変更して、一定時間使われないプロセスはすべて終了するようにした。
    FcgidMinProcessesPerClass	0
    FcgidProcessLifeTime		600
    FcgidIdleScanInterval		120
    

スワップは実RAMの倍(この場合2GB)という定説を昔読んだ気がしますが、「未開放メモリ→スワップアウト」というケースを考えると、多いに越したことはないかもしれません。

本当はApache側でメモリ制限を実施できたら楽なのですが、mod_fcgidの子プロセスには RLimitMem とか効かないんですよね……。

参考サイト

2022/05/20(金)Dell S150 に Software RAID で Ubuntu 22.04 をインストール

Dell PowerEdgeサーバに乗っているなんちゃってRAIDコントーラーS150を使用した状態で、Ubuntu Desktop 22.04をインストールしたメモ。

S150とは

よくあるBIOSでRAID化するだけの、実質ソフトウェアRAIDです。S150はLinuxのRAIDに対応しており、BIOSからLinuxで作成したRAID情報を参照できるようです。

つまりRAID化した状態でLinuxをインストールすることができれば、そのRAID化されたディスクから起動することも可能です。

Ubuntu Desktop 22.04のインストール

ミラーリング(RAID1)に設定する場合。

  1. BIOSの設定からSATAのモードを「AHCI」から「RAID」に切り替えます。
  2. Ubuntu Desktop 22.04をインストールイメージから起動します。
  3. インストールではなく「Ubuntuを試用する」を選択します。
  4. Terminalを開き、mdadmをインストールします。
    sudo apt-get install mdadm
    
  5. ディスク全体でRAIDを構築します。
    sudo mdadm --create md0 --level=1 --raid-disk=2 /dev/sda /dev/sdb
    
    /dev/md127 として認識されます。
  6. この状態で、Ubuntuをインストールします。インストール先はディスク全体を削除してインストール(自動選択でmd127)です。md127に2つのパーティションが作られます。
  7. 「grub-install /dev/sda の実行に失敗しました」というメッセージが出たら再起動せずにウィンドウを閉じます。
  8. /targetにRAIDディスクの/(md127p2)がマウントされていますので、ターミナルで以下の操作をします。
    sudo su
    cd /target
    mount --bind /dev dev
    mount --bind /sys sys
    mount --bind /proc proc
    cp /etc/resolve.conf etc/
    chroot .
    mount /boot/efi
    apt install mdadm
    grub-install
    
    これにより /boot/efi に必要なファイルが配置されますが、EFIブートメニューへの登録には失敗します。
  9. EFIブートメニューに項目を登録します。
    efibootmgr -c -d /dev/md127 -p 1 -L "ubuntu" -l '\EFI\ubuntu\shimx64.efi'
    

あとはターミナルを抜けて普通に再起動すれば、RAID状態のディスクからUbuntuが起動します。

メモ

# EFIメニュー登録状態の確認
efibootmgr -v
# EFIメニューの項目削除
efibootmgr -B -b 0001
# Software RAIDの状態確認
cat /proc/mdstat
# /etc/defult/grub
GRUB_RECORDFAIL_TIMEOUT=3
GRUB_DISABLE_SUBMENU=y

カーネルだけ更新

v5.17.9の場合。

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.17.9/amd64/linux-headers-5.17.9-051709-generic_5.17.9-051709.202205180947_amd64.deb
wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.17.9/amd64/linux-headers-5.17.9-051709_5.17.9-051709.202205180947_all.deb
wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.17.9/amd64/linux-image-unsigned-5.17.9-051709-generic_5.17.9-051709.202205180947_amd64.deb
wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.17.9/amd64/linux-modules-5.17.9-051709-generic_5.17.9-051709.202205180947_amd64.deb
wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.17.9/amd64/linux-modules-iwlwifi-5.17.9-051709-generic_5.17.9-051709.202205180947_amd64.deb

dpgk -i *.deb

2022/03/09(水)OpenWrtでIPv6とDS-LiteとPPPoEを全部使う

OpenWrtを設定&構築したメモ。DS-LiteではなくMAP-Eでも参考になるかと思います。

※Linuxおよびネットワークの知識がない方はOpenWrtには手を出さないでください。

ことの発端

家庭内ルーターとして「NEC Atermシリーズ」を使っていたのですが、性能は申し分ないものの問題点があります。

  • 最新機種でもDS-Lite使用時PPPoEをパススルーできない*1
  • そのせいで、PPPoEとDS-Liteの併用ができない。*2
  • LAN内にDNSサーバを立てるとルータのDNSマスカレード機能が不安定になる。

WG1200HSはDS-Lite非対応なので、PPPoEと併用可能なら新しいのに買い替えてもよかったのですが、こんな状況ではAtermが選択肢に入らない。かといってBuffaloは安定性に問題ありそうなので、いっそのことOpenWrtルーターすればよいのでは? と。

*1 : DS-Lite以外ほぼすべての設定でパススルー可能であるのに、DS-Liteだけは絶対に許可しないという謎仕様を貫き通すNEC。

*2 : PPPoEをメインにしてLAN内のLinux等でDS-Liteを構築することは可能ですが、それは求めていない。

構築目標

openwrt-network.png

  • PPPoEとDS-Liteを併用する
  • LAN内の一部のマシンのみPPPoE側を使用する。

前提条件

  • ルーターのWAN側にはONU(光回線終端装置)が接続されている。
  • IPv6オプション(IPv6ネイティブ通信)が利用可能になっている。
  • DS-Lite(or MAP-E等)が使える状況になっている。
  • PPPoEが使える状況になっている(プロバイダ側で併用が許可されている)。

続きを読む

2021/12/24(金)ESP32 SDKのカスタムビルドを使った開発環境作り

BluetoothSerialのWindowsのCOMポート接続不良問題

ESP32標準SDKのBluetoothには、WindowsのBluetooth 5.0以降のアダプタから接続したとき、うまく接続されない既知の不具合があります。

BluetoothSerial(SerialBT)ですと、Windows側から接続を開始したときに

ASSERT_WARN(103 23), in lc_task.c at line 8775

というエラーが表示され、接続に失敗します。これを解決するために、SDKをリビルドし、リビルドした開発環境を構築することを目的とします。

続きを読む