システムログ肥大化とその対処設計

Linux を長く運用していると、CPU 使用率やメモリー使用量よりも先に、ログがシステム全体の安定性を壊すことがある。systemd-journald はカーネルメッセージ、syslog、サービスログなどを収集する基盤であり[1]、journald.conf では保存量そのものに上限を設けることもできる[2]。一方、Debian では rsyslog が古典的なテキストログ基盤として広く使われており[3]、logrotate は /var/log 配下のログを日次やサイズ条件で循環させる標準手段になっている[4][5]。つまり、現代の Debian 系システムでは「journald が集め、rsyslog が syslog を書き、logrotate が古いログを回す」という三層構造を前提に考える必要がある[6]

今回の出来事は、その三層構造のどれか一つが壊れたというより、「syslog は残したい」「90 日保持したい」「しかし 10 GB 超の単一ファイルは作りたくない」という複数の要求がぶつかった例だった。しかも、問題の中心は GPU の詳細原因や特定ドライバーの癖よりも、「ログスパムが発生したとき、どの価値を守り、どこで割り切るか」という運用思想のほうにあった。本稿では、実際に起きた事象を起点として、調査で何を見たか、どこで誤解しやすかったか、最終的にどのように運用設計へ落としたかを順に整理する。

項目 今回の前提 意味
ログ基盤 journald + rsyslog + logrotate 収集、保存、循環が別レイヤで動いている。
保持方針 syslog を 90 日保持 短期分析だけでなく、過去比較にも使う前提である。
今回の障害像 syslog が 10 GB 超に肥大化 単なる「ログが多い」ではなく、運用設計の限界が露出した。

1. まず何が起きたのか

最初に観測されたのは、/var/log/syslog が約 12 GB に達していたという事実である。ここで重要なのは、これは「90 日保持の結果として徐々に増えた」のではなく、短時間に単一ファイルが異常に大きくなったという点である。logrotate は、本来こうしたログ肥大化を避けるための標準機構であり、日次、週次、月次、あるいはファイルサイズを条件にローテーションできるよう設計されている[4][7]。にもかかわらず単一の syslog が 12 GB まで伸びたということは、少なくともその時点の構成では、短時間スパイクに対する防御が不足していたと読める。

この時点でやるべきことは、原因をすぐに断言することではなく、現象を分解することである。syslog が大きいという結果だけを見ていると、「ディスクが足りない」「rsyslog が壊れた」「logrotate が動いていない」といった複数の仮説が同列に並ぶ。しかし実際には、「ログが書かれすぎた」のか、「回転が間に合わなかった」のか、「保持設計が短期スパイクを想定していなかった」のかで、対策はまったく変わる。

観測事実 直感的な見え方 実際に切り分けるべき論点
syslog が 12 GB logrotate が壊れたように見える。 出力量の異常か、回転条件の不足か、保持思想の不足かを分けて考える必要がある。
GUI が不安定 GPU 障害のように見える。 GPU そのものより、ログスパムと表示系の不整合が別系統で重なっていないかを見る必要がある。
SSH は生きている 完全障害ではない。 OS 本体は稼働しており、調査と復旧をシステム外から継続できる状態だった。

2. 調査で見たこと

今回の調査で最初に重要だったのは、時系列を崩さないことだった。後からカーネルパラメーターを触り、表示系をいじり、GDM の復旧も行ったが、syslog の肥大化そのものはそれ以前から起きていた。したがって、この設定変更は「GUI の混乱」には関係しても、「最初に syslog が膨張した理由」そのものとは分けて考えなければならない。ここを混同すると、後からやった作業を真因と誤認しやすい。

次に、Linux の表示系を少しでも触っていると、GPU 周辺のログを真っ先に疑いたくなる。実際、Kernel Mode Setting はカーネル空間でディスプレイ解像度やフレームバッファを初期化する仕組みであり[8]、DRM/KMS は起動時やディスプレイの状態変化で多くのログを出しうる。しかし、ここで重要なのは「GPU が怪しいかどうか」より、「GPU を含むどこかが高頻度の繰り返しログを出している可能性がある」という観点である。ログスパムは、原因の種類よりも、頻度と継続時間の積によって容量を破壊するからだ。

また、rsyslog の入力経路にも目を向ける必要がある。rsyslog の imuxsock は Unix ソケット経由の古典的な syslog 入力モジュールであり、rate limiting を備えている[9][10][11]。一方で repeated message reduction のような「同じログを “Last message repeated n times” のように畳み込む」機能も存在するが、rsyslog 自身がこれを古い運用向けの機能と見なしており、現代的なログ解析では副作用もあると明記している[12]。つまり、ログスパム対策は存在するが、「雑に全部まとめればよい」というほど単純ではない。

調査項目 見た理由 要点
syslog のサイズと時系列 いつから肥大化していたかを固定するため。 後から触った設定と、最初の肥大化を分離して考える必要がある。
GPU / DRM / KMS 周辺 表示系ログは大量出力の候補になりやすいため。 GPU の善悪ではなく、高頻度反復の可能性として扱うべきである。
rsyslog の入力機構 保存前に抑制できる場所がどこかを確認するため。 rsyslog には rate limiting 系の仕組みがあるが、何を守るかで使い方が変わる。

3. 途中で陥った誤解

今回、途中で最も誤解しやすかったのは、「後から触ったカーネルパラメーターや Xorg 設定が、syslog 肥大化の根本原因でもある」と見えてしまう点だった。実際には、カーネルパラメーター変更や手動の Xorg 設定は、後段の GUI 不調を複雑にしたが、syslog が巨大化していた事実そのものは先に存在していた。この順番を取り違えると、復旧作業の副作用と元の問題が一つに見えてしまう。

もう一つの誤解は、「原因を完全に突き止めなければ設計を決められない」という発想である。もちろん、原因が確定すればより鋭い対策は打てる。しかし長期運用の設計では、原因の種類よりも先に、「同じようなスパイクが再発したときにシステムを壊さない」ことが重要になる。systemd-journald はログ収集と保存の基盤であり[1][13]、journalctl で後追い分析もできる[14]。それでも、日々の運用で主に参照するのが /var/log/syslog なら、syslog 自体の保存設計を詰める必要は残る。

さらに、rsyslog を journald に戻す構成や、逆に journal だけで運用する構成も理論上はありうる。だが Debian では rsyslog は今も標準的なテキストログ基盤として使われており[3][18]、今回の前提でも syslog は廃止しない。したがって議論の軸は、「syslog をやめるかどうか」ではなく、「残したままどこまで守るか」に置くのが自然だった。

誤解 なぜ起きやすいか 修正後の理解
後からいじった設定が真因だと思う。 復旧作業の直後に症状が変わるため。 元の肥大化と後段の GUI 不調は時系列で分ける必要がある。
原因を完全特定しないと設計できない。 障害解析と運用設計を同一視しやすいため。 設計は「再発時に何を守るか」の優先順位で決められる。
syslog をやめればよい。 journald があるため代替可能に見えるため。 今回の前提では syslog を残す。問題は存在ではなく運用の条件である。

4. 問題の本質は何だったのか

ここでようやく問題を抽象化できる。今回の本質は、「原因が GPU か rsyslog か」ではない。問題は、ログ量を時間だけで管理していたことにある。ログファイルの総量は、単純化すれば「出力頻度 × 継続時間」で決まる。日次ローテーションだけを前提にすると、通常時のゆるやかな増加には強いが、短時間で異常に高頻度な出力が起きた場合には脆い。logrotate の man page が示すように、logrotate は時間条件でもサイズ条件でも回せるが[4][7]、時間だけに依存している限り、短期スパイクはその日一杯まで単一ファイルに蓄積される。

Debian の Policy も、ログは無限に成長させてはならず、適切にローテートすべきだと明言している[5]。Debian Handbook も、/etc/logrotate.d に置く方針を管理者が調整できると述べている[6]。つまり、今回の 10 GB 超問題は「想定外の例外」というより、「期間ベース設計だけでは頻度異常に弱い」という、logrotate の前提どおりの限界が表面化した例だと理解したほうが正確である。

視点 期間ベースだけの設計 今回露出した弱点
通常時 1 日 1 回の循環で十分機能する。 問題は見えにくい。
短期スパイク時 次のローテーションまで現行ファイルに溜まり続ける。 単一ファイルが巨大化する。
設計上の本質 時間は見ているが頻度を見ていない。 「急に増える」事象への耐性が弱い。

5. では何を守るべきか

この段階で議論は技術から価値判断に移る。今回の検討で最も重要だったのは、「異常時のログを全部残す必要があるのか」という問いだった。結論は、全部残す必要はない、である。なぜなら、ログスパムの多くは「新しい情報が増え続けている」のではなく、「同じ種類の情報が高頻度で繰り返されている」だけだからだ。rsyslog に repeated message reduction があること自体、古くからこの問題が存在していたことを示している[12]。ただし、その機能を常時有効化すると、後からの解析で不都合もある。だからこそ、理念としては「すべての重複を圧縮する」のではなく、「守るべきものの優先順位を決める」ことが先になる。

今回の優先順位は明確だった。第一に守るべきなのはシステムの安定性、第二に守るべきなのは通常時の 90 日履歴、第三に異常時スパムの完全保存、という順である。この順序に立つと、「単発のスパム日のすべてを無制限に残す」よりも、「そのせいで過去 90 日の通常履歴や system 全体の安定性が壊れない」ことのほうが重要になる。ここを言語化できたことで、設計の割り切りが可能になった。

優先順位 守る対象 理由
1 システムの安定性 ログのために OS が不安定になるのは本末転倒だからである。
2 通常時の 90 日履歴 日々の比較や障害前後の差分確認に価値があるからである。
3 異常時スパムの完全保存 重複の多い大量ログは容量を食う割に情報価値が低いからである。

6. syslog に余計なメッセージを書かせないという処置

今回、保存側の設計だけを見直したわけではない。/etc/rsyslog.d の下に追加の設定ファイルを置き、明らかに不要なメッセージを syslog に書かせない処置も入れた。これは「原因そのものを直した」というより、「少なくとも syslog という共通ログに、価値の低い反復メッセージを流し込み続けない」という方針に基づく。rsyslog は設定ファイルを /etc/rsyslog.d 配下に分割配置でき、条件分岐や stop ルールによるフィルタリングも可能である[19][20][21]

ここで重要なのは、これは「ログを隠す」のではなく、「syslog に保存する価値のあるログだけを通す」という選別だという点である。すべてのログが同じ価値を持つわけではない。特に、同一種のノイズが大量に反復される場合、それを全部 syslog に記録することは、診断能力を高めるどころか、通常時の履歴やディスク余裕を食いつぶして system 全体を不安定にする。共有ログは全量保存の場ではなく、運用上意味のある情報を残す層である、という理解に立たなければこの判断はできない。したがって、今回の思想は「ログは全部残すもの」ではなく、「共有ログに流す段階で選別すべきもの」という方向へ寄っている。

今回実際に抑止したのは、GPU ドライバーが出力する低レベルな内部処理ログである。これらは GPU の自己診断やコマンド投入に関する逐次イベントであり、カーネル開発やドライバー解析の局面では意味を持つ。しかし通常運用では、高頻度に反復される一方で、共有ログとしての価値は低い。今回無視した対象を整理すると、次のようになる。

フィルタ条件 無視しているもの 実際の意味 運用上の判断
ring test GPU のコマンドリング動作確認ログ GPU 内部のコマンドキューが動くかどうかを確認する自己テストである。 高頻度で反復されやすく、通常運用の syslog に残す価値は低いと判断した。
ib test Indirect Buffer の実行経路テストログ GPU に渡すコマンドバッファが正しく流れるかを確認する内部テストである。 内部実行経路の確認ログであり、反復時はノイズ化しやすいため除外対象とした。
schedule ib / schedule IB GPU への処理投入イベントログ GPU の実行キューにジョブを投入したことを示す内部スケジューリングログである。 逐次イベントとして大量発生しやすく、共有ログの可読性を著しく下げるため除外対象とした。

要するに、ここで無視しているのは GPU 障害そのものではなく、GPU 内部の反復的な処理イベントである。ring test、ib test、schedule ib はいずれも「GPU がいま何を内部で試し、何を投入したか」という逐次ログであり、通常運用の syslog で長期に追跡したい種類の情報ではない。逆に、初期化失敗、ハング、リセット、致命的エラーのような、状態変化や障害を示すシグナルまで丸ごと捨てる設計は採っていない。ここで切っているのは、あくまで高頻度・低情報量のノイズである。

1
2
3
4
:msg, contains, "ring test" stop
:msg, contains, "ib test" stop
:msg, contains, "schedule ib" stop
:msg, contains, "schedule IB" stop

もちろん、フィルタには副作用がある。捨てたメッセージは後から読めない。だから、何でもかんでも stop すればよいわけではない。今回のように「明らかに価値が低く、しかも高頻度に反復されるメッセージ」に限定して抑止するからこそ、通常履歴の価値を守る設計になる。rsyslog には rate limit や repeated message reduction の系統もあるが[9][10][11][12]、今回はそれらを全面的な中心機能にするのではなく、明示的なフィルタと保存側の制御を組み合わせる考え方を採った。

言い換えると、今回の対策は「入力制御」と「出力制御」の二段構えになっている。入力制御とは、rsyslog のフィルタでそもそも syslog に書かせないことであり、出力制御とは、logrotate の maxsize で万一流入した場合にも単一ファイルの肥大化を防ぐことである。syslog は、何でもかんでも捨てずに溜め込む倉庫ではない。選別された情報だけを蓄積する層として扱うべきであり、その意味で今回の /etc/rsyslog.d の設定は単なる小技ではなく、ログ観そのものの修正だった。

対策レイヤ 今回の処置 意味
入力制御 /etc/rsyslog.d のフィルタ設定 価値の低いノイズを syslog に流し込まない。
出力制御 logrotate の maxsize 万一流入しても単一ファイル肥大化を防ぐ。
背景思想 書かない設計と溜めない設計の両立 入口と出口の両方で system を守る。

7. 設計要求どうしが衝突した点

ここで一つの難しさがある。今回の運用には、すでに「syslog.1 を前提にした番号ローテーション」と「90 日保持」という既存設計があった。しかもその方針は、自分の scripts 群の中でも setup_rsyslog_logrotate.sh に反映されている[17]。この既存設計を壊さずに、短期スパイクだけを防ぎたい。ここが今回の設計上の衝突点だった。

もし dateext のような別命名へ全面移行すれば、日付単位の管理はしやすくなる。しかし syslog.1 を前提とした既存運用は壊れる。逆に rotate 90 のままで size や maxsize を入れると、通常時は今まで通りでも、異常日にローテーション回数が増えて世代消費が早くなり、過去ログが押し出される可能性がある。このトレードオフを見たときに、「理想的に全部を同時に守る」のではなく、「どれを優先してどれを受け入れるか」を先に決める必要があると分かった。

要求 守れるもの 崩れやすいもの
syslog.1 前提を維持したい。 既存運用の互換性 異常時の柔軟な命名管理
90 日保持を維持したい。 通常時の比較可能性 スパイク時の完全保持
単一ファイル肥大化を防ぎたい。 ディスク安全性 異常日の全量保存

8. 最終的にどう考えたか

ここまで整理すると、答えはかなり単純になる。今回は、異常時ログの完全保存を最優先しない。したがって、通常運用の互換性を壊さずに、単一ファイル肥大化だけを防ぐ方向へ寄せるのが自然だった。logrotate は、時間条件に加えて「ファイルが一定サイズを超えたら、その時点でも回す」という maxsize を持っている[4]。これを使えば、通常時にはこれまで通りの daily + rotate 90 の挙動を保ちつつ、異常時だけ追加ローテーションが発動する。

もちろん、この方式には明確な代償がある。ログスパムが激しい日に何度も回れば、そのぶん世代消費が進み、古いログが押し出される可能性は残る。しかしこれは、今回の価値判断と整合している。すなわち、「異常時スパムを全部残すこと」より「10 GB 超の単一ファイルを作らないこと」と「通常運用の互換性を崩さないこと」を優先する、という判断である。完全解ではないが、既存設計を壊さずに防御線を一段だけ増やす、という意味では非常に実務的である。

候補 利点 欠点
dateext などへ全面移行 日付管理は明確になる。 syslog.1 前提の既存運用を壊す。
追加スクリプトで overflow を分離 通常履歴と異常ログを分けやすい。 運用が複雑になり、作り込みが増える。
maxsize を追加する 通常時の互換性を保ちつつ、巨大単一ファイルを防ぎやすい。 異常時は世代消費が速くなり、過去ログ押し出しの可能性は残る。

9. 運用設計に落とした結果

最終的に採ったのは、daily と rotate 90 を維持したまま、maxsize を追加するという最小変更だった。logrotate の man page どおり、maxsize は時間条件に加えてサイズ条件でもローテーションを起動できる[4]。この選択の意味は、「何も起きなければ今まで通り」「異常時だけ追加で回す」である。つまり、普段の見え方は変えず、事故のときだけブレーキをかける。言い換えれば、maxsize は時間軸の設計に追加された、容量軸のブレーキである。

ここで重要なのは、この設定を「完全にすべてを守る仕組み」と誤解しないことだ。これはあくまで、既存設計を崩さずに致命傷を減らすための小さな防御である。さらに今回は、/etc/rsyslog.d 配下のフィルタで syslog に書かせない処置も入れている。つまり、保存前にノイズを落とし、保存後に巨大化を抑えるという二段構えになっている。rsyslog には rate limiting もあり[9][10][11][16]、imjournal より imuxsock のほうが軽く高速だという upstream の説明もある[15]。しかし今回の焦点は、入力経路の作り込みを増やすことではなく、今の syslog 運用に「最小限の安全弁」を追加することにあった。その意味で、rsyslog フィルタと maxsize の組み合わせは、設計思想と実装量のバランスが最もよかった。

実際の設定は syslog だけでなく、mail.log、kern.log、auth.log、user.log、cron.log を含む主要ログ群全体に対して同じ方針を適用している。本文では syslog を主軸に議論しているが、実運用では「単一の代表ログだけを守る」のではなく、rsyslog 管理下の主要ログ群に対して同じ容量軸のブレーキを入れた、という理解が正確である。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/var/log/syslog
/var/log/mail.log
/var/log/kern.log
/var/log/auth.log
/var/log/user.log
/var/log/cron.log
{
    rotate 90
    daily
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        /usr/lib/rsyslog/rsyslog-rotate
    endscript
    maxsize 100M
}

本稿では syslog を主軸に議論しているが、実運用では rsyslog 管理下の主要ログ群全体に同じ設計を適用している。

状態 挙動 意味
通常時 1 日 1 回のローテーションが中心 見た目の運用はほぼ従来通りになる。
異常時 100 MB を超えた時点で追加ローテーション 単一ファイルが極端に巨大化する事態を避けやすくなる。
保存前対策 rsyslog フィルタで不要メッセージを落とす 低価値なノイズを共有ログへ流し込まない。
代償 スパム日は世代消費が速くなり、捨てたログは戻らない 異常時の全量保存より、通常運用の互換性と安全性を優先する設計である。

10. 今回の事象から得た教訓

今回の件で一番大きかったのは、「ログは残すか捨てるか」という単純な二択ではなく、「どのログをどの優先順位で守るか」を先に決めないと、設定論が迷走するという事実だった。ログは本質的に診断情報であって、量そのものに価値があるわけではない。systemd の journal は構造化された保存基盤として強力であり[1][14]、rsyslog は高性能で柔軟なテキストログ基盤であり[3][19]、logrotate はその保存期間と容量管理を担う[4][6]。しかし、三者をどう組み合わせても、「異常時の全量保存」と「通常履歴の維持」と「運用の単純さ」を全部 100 % 満たすことは難しい。

その意味で、今回の結論はかなり現実的だった。すなわち、syslog は維持する。90 日保持の番号ローテーションも維持する。その代わり、異常時スパムの完全保存は諦め、単一巨大ファイルを防ぐために maxsize を加える。さらに、そもそも syslog に流し込むべきでないノイズは /etc/rsyslog.d のフィルタで落とす。これは華やかな解ではないが、長期運用ではむしろこの種の地味な割り切りのほうが効く。Debian でも、ログは肥大化しうるためローテートすべきだという前提が繰り返し確認されている[5][6]。今回の出来事は、その一般論を、自分の運用条件に照らして具体的に言い直した例だった。

今回の判断は、syslog を廃止せず、90 日保持を維持しつつ、入力制御と出力制御によってログの振れ幅を抑える設計だった。最後に一文でまとめるなら、こう表現できる。ログは保存対象である前に、制御対象である。何を記録し、何を共有ログから外し、どこでブレーキをかけるかを設計しない限り、ログは診断資源ではなく障害要因に変わる。逆に言えば、量ではなく選別と構造でログを捉え直すことで、初めて syslog は長期運用に耐える基盤になる。

教訓 今回の形で言い直すと 運用上の意味
原因究明と設計は分ける。 真因未確定でも、守る価値の順位は決められる。 障害解析が長引いても運用改善を止めなくてよい。
時間だけでは足りない。 短期スパイクにはサイズ条件が必要になる。 「90 日保持」だけでは単一巨大ファイルを防げない。
完全保持を目標にしない。 異常時スパムより、通常履歴とシステム安定性を優先する。 設定がぶれにくくなり、判断も速くなる。
保存前にも手を入れる。 書かない設計と溜めない設計を両立する。 入口と出口の両方でシステムを守る発想が必要になる。

参考文献

  1. systemd-journald.service. https://www.freedesktop.org/software/systemd/man/systemd-journald.service.html
  2. journald.conf. https://www.freedesktop.org/software/systemd/man/journald.conf.html
  3. Debian, Details of package rsyslog in trixie. https://packages.debian.org/rsyslog
  4. logrotate(8), Debian testing manpage. https://manpages.debian.org/testing/logrotate/logrotate.8.en.html
  5. Debian Policy Manual, Chapter 10 Files. https://www.debian.org/doc/debian-policy/ch-files.html
  6. Debian Handbook, Other Configurations: Time Synchronization, Logs, … https://www.debian.org/doc/manuals/debian-handbook/sect.config-misc.hr.html
  7. logrotate(8), Linux man-pages project. https://man7.org/linux/man-pages/man8/logrotate.8.html
  8. Linux Kernel Documentation, Kernel Mode Setting (KMS). https://docs.kernel.org/gpu/drm-kms.html
  9. rsyslog, imuxsock: Unix Socket Input Module. https://docs.rsyslog.com/doc/configuration/modules/imuxsock.html
  10. rsyslog, RateLimit.Interval. https://docs.rsyslog.com/doc/reference/parameters/imuxsock-ratelimit-interval.html
  11. rsyslog, SysSock.RateLimit.Interval. https://docs.rsyslog.com/doc/reference/parameters/imuxsock-syssock-ratelimit-interval.html
  12. rsyslog, $RepeatedMsgReduction. https://docs.rsyslog.com/doc/configuration/action/rsconf1_repeatedmsgreduction.html
  13. journald.conf(5), Debian testing manpage. https://manpages.debian.org/testing/systemd/journald.conf.5.en.html
  14. journalctl. https://www.freedesktop.org/software/systemd/man/journalctl.html
  15. rsyslog, imjournal: Systemd Journal Input Module. https://docs.rsyslog.com/doc/configuration/modules/imjournal.html
  16. rsyslog, Features. https://docs.rsyslog.com/doc/features.html
  17. id774, scripts/doc/VERSIONS at master. https://github.com/id774/scripts/blob/master/doc/VERSIONS
  18. Debian Reference Japanese PDF. https://www.debian.org/doc/manuals/debian-reference/debian-reference.ja.pdf
  19. rsyslog Documentation Index. https://docs.rsyslog.com/doc/index.html
  20. rsyslog, Actions and Filters. https://docs.rsyslog.com/doc/configuration/actions.html
  21. rsyslog, Basic Structure. https://docs.rsyslog.com/doc/getting_started/basic_configuration.html