背景
CentOS 7 で、とあるサーバを構築し、負荷試験を実施したところ systemd-journald がCPU100%使い切っており、本来のパフォーマンスが発揮されないことが判明しました。
レガシーの syslog() で秒間数万行以上の大量のログを出力しており、systemd-journald プロセスの処理が追いつかず /dev/log ソケットでメッセージが詰まってしまったことが原因でした。
根本的な原因は syslog() で大量のログを出力していることにあるのですが、systemd-journald も結局は rsyslog に転送してログファイルに書き出しているだけなので、ボトルネックになってほしくはありません。
systemd-journald が高負荷になった原因については、詳しくは調べていません。おそらくはメッセージの付属情報の取得やバイナリデータ用のデータベースへの書き込みなどの処理にあると思っています。
また、syslog() は、rsyslog でログファイルに書き込んでいます。そのため、systemd-journald のバイナリログと rsyslog のログファイルの両方に保存していることなるので systemd-journald を経由することは、はっきり言って無駄な処理となっています。
そのため、sytemd-journald を経由せずに直接 rsyslog で /dev/log を使う設定を調査しました。
設定
/dev/log は Datagram ベースの UNIX-domain socket です。
# fuser -v /dev/log USER PID ACCESS COMMAND /dev/log root 1 F.... systemd root 6277 F.... systemd-journal # netstat -x | grep dev unix 3 [ ] DGRAM 103043 /dev/log
systemd-journald.socket ファイルの /dev/log をコメントアウトします。
[Socket] ListenStream=/run/systemd/journal/stdout ListenDatagram=/run/systemd/journal/socket #ListenDatagram=/dev/log #コメントアウト
rsyslog の SystemLogSocketName を設定を変更します。
#$SystemLogSocketName /run/systemd/journal/syslog #コメントアウト $SystemLogSocketName /dev/log #デフォルト値なので記述しなくてもいいのですが、書いたほうが分かりやすいと思います
rsyslog の設定を変更します。
$ModLoad imuxsock #アンコメント #$ModLoad imjournal #コメントアウト $OmitLocalLogging off #off に変更 #$IMJournalStateFile imjournal.state #コメントアウト #$imjournalRatelimitInterval 0 #記述した場合はコメントアウト #$imjournalRatelimitBurst 0 #記述した場合はコメントアウト
systemd-journald と rsyslogd の再起動します。
# systemctl restart rsyslog # systemctl status rsyslog →status でエラーがないことを確認。 # systemctl restart systemd-journald # systemctl status systemd-journald →status でエラーがないことを確認。
/dev/log を掴んでいるプロセスを確認します。
# fuser -v /dev/log USER PID ACCESS COMMAND /dev/log root 1 F.... systemd root 9218 F.... rsyslog root 9234 F.... systemd-journal
systemd-jounral が /dev/log を掴んだままであれば、OS再起動をします。
# reboot ... 再起動後... # fuser -v /dev/log USER PID ACCESS COMMAND /dev/log root 1 F.... systemd root 128 F.... rsyslog
これで rsyslog で直接 /dev/log を取得できるようになりました。
sytemd-journald 自体のログ収集は止めていないため モダンな /run/systemd/journal/socket ソケットからのログは journalctl で検索可能です。
補足
この方法は、おそらく CentOS 7 でしか利用できません。別のディストビューションの場合、/dev/log は /run/systemd/journal/dev-log のシンボリックリンクになっている場合があります。