systemd-journaldの1ログ行がディスク書き込み49KB超(ext4)/110KB超(btrfs)に
Single log line is 49KB+ (ext4) / 110KB+ (btrfs) of systemd-journald disk writes

systemd-journaldが過剰なI/Oを引き起こす問題がGitHubで報告され、コミュニティで注目を集めています。報告者によると、1秒あたり2行のログを書き込むだけでVMが約50 IOPSを消費し、1行のログ書き込みがext4で49KB以上、btrfsで110KB以上のディスク書き込みにつながるとのこと。XFS上のVMで再現し、journaldの非効率なフォーマットが原因と指摘。コメントでは、圧縮無効化を試す提案や、15分で約7GBの書き込みを観測したユーザーの報告、メモリプレッシャーによるキャッシュフラッシュの頻発など、追加の証拠が示されています。
journaldは非常に非効率なフォーマットを使用しており、ファイルのサイズも実際に書き込まれるデータの数倍になるため、不潔な再起動で破損することも何度か見てきました。
HNでの議論
223- pengaru
私はおそらくjournaldを何とか使えるようにした主な責任者です。
しかし、ディスク上の構造や書き込み方法を変える努力は実際にはほとんどしませんでした。私の焦点はどちらかというとjournalctlの読み取りパフォーマンスとデーモンの安定性にありました。
ずっと昔、CoreOSでjournaldの問題を修正するために給料をもらっていた頃、それは自分のサービスのウォッチドッグに殺されることさえ避けられませんでした。
当時の私の印象では、ディスク上のフォーマットは同じファイル内で情報を分散させすぎており、個々のデータが不連続なオフセットに書き込まれるため、それらは非常に小さく、IOブロックサイズやディスクセクタサイズよりもはるかに小さかったです。
これはファイルフォーマットによる書き込み増幅の問題のように思えました。ファイル内の任意の位置に数バイト書き込むと、その一部だけを変更したにもかかわらず、ストレージはブロック全体を書き戻さなければなりません。もしその数バイトがブロック境界をまたぐ場合、どうなると思いますか? 2つのブロックが書き込まれます。
フォーマットはこれらのブロック指向のストレージの詳細を考慮しておらず、mmap経由でIOを行うことは、カーネルが非同期にプリフェッチするものを推測しなければならないため、傷口に塩を塗るようなものです...しかし、その側面がプレーンなバッファIOよりも書き込みを増幅させるとは思いません - もしかしたら間違っているかもしれません。mmapの側面は、読み取りの増加や誤予測を引き起こし、ページキャッシュを無関係なコンテンツで汚染すると思います(十分なメモリがあれば、ジャーナル全体がキャッシュされる傾向があると思います)。おそらく...
- otterley
途中で何かが起こったに違いありません。なぜなら、これはデータベースの当初の設計意図ではなかったからです(強調は私によるものです):
"""
ネイティブジャーナルファイル形式は、古典的なログファイルとgitリポジトリに触発されています。ログデータが最後にのみ追加されるように設計されており(mmap()ベースのアクセスでの堅牢性と原子性を確保するため)、新しい追加を参照するためのいくつかのメタデータ変更がヘッダーに行われます。エントリが構成するフィールドは、ジャーナルファイル内の個々のオブジェクトとして保存され、それらを必要とするすべてのエントリによって参照されます。これにより、ジャーナルエントリは通常非常に反復的であるため(すべてのローカルメッセージに同じ_HOSTNAME=と_MACHINE_ID=フィールドが含まれると考えてください)、ディスクスペースを大幅に節約できます。データフィールドはディスクスペースを節約するために圧縮されます。正味の効果は、ジャーナルが従来のsyslogよりもかなり多くのメタデータを記録するにもかかわらず、ディスクフットプリントがすぐにはそれを反映しないということです。
"""
https://docs.google.com/document/u/0/d/1IC9yOXj7j6cdLLxWEBAG... を参照してください。
- adrian_b
そこでのコメントの一つに完全に同意します:
> しかし、根本的な結論は:設計が間違っていた。mmapped書き込みを使うべきではなかった。pwriteの方がはるかに良かったでしょう。
ログを書くときにメモリマップドファイルを使うのは本当に意味がありません。
pwriteでさえ意味がありません。なぜなら、ログは通常、ログファイルを追記専用のシーケンシャルファイルとして開いて使用することで書かれるべきだからです。
ログを読むときだけ、問題を検索するために、読み取り専用のメモリマップドファイルとしてアクセスするのは問題ありません。
実際、ログだけでなく、ほとんど常に、読み書き可能なメモリマップドファイルは非効率か、使用が複雑すぎます(つまり、問題を避けるためにmsyncやmadviseを注意深く使用する必要があり、メモリマップドファイルがpread/pwriteよりも好まれる単純さを失います)。メモリマップドファイルは、openとmmapで適切なオプションフラグを使用して、読み取り専用アクセスのためだけに使用する方が良いです。
- 0x_rs
journaldは多くの理由でひどいですが、それを悪化させているのは、マシン上で実行されているすべてのものが、求められなくても好きなだけログをダンプする権利があると思っていることです。ファイルピッカーを開くと、kioが1日に数万から数十万のエントリをスパムするのは良い考えだと判断し、ディレクトリ内のすべてのファイルをリストアップして「削除されたばかりのアイテムのノードが見つかりません」のようなログを出力しますが、それはユーザーにまったく影響を与えません。新しいサービスごとにジャーナルの洪水を追跡するスクリプトをほぼ維持する必要があり、システムログを捨て場として扱っていないか確認する必要があります。公平に言うと、カーネルやUSB周辺機器も悪い日には1時間に300万行をスパムすることがあり、入力IRQステータス-75などを考えてください。
すべてのプログラムレベルの設定(もしあれば)とサービスファイルを追跡するのは大変ですが、systemdのLogFilterPatternsは意図しない方法で役立ちます:/etc/systemd/system/service.d/の.confファイルで1つのログブラックリストを作成し、ジャーナルをスパムするすべてのパターンを1つずつそこに入れることができます。誤ったログレベルを追跡する必要さえありません。次のようになります:
[Service]
LogFilterPatterns=~I am a completely useless log entry
LogFilterPatterns=~I am another useless log entry
しかし、識別子を拾わず、カーネルのスパムには何もしません。いくつかのメッセージを黙らせるのにだけ役立ちます。また、キャッシュやジャーナルなどにnocowがないbtrfsインストールは欠陥があると思います...
- jck86
ケーキの上のチェリーは、journaldを実際にはフィルタリングできないことです。唯一のオプションは重大度で制限する(例:エラー以上)か、非永続的なjournaldストレージに切り替えてrsyslogに転送し、そこでフィルタリングすることです。
詳細は少し曖昧ですが、時々ドライバーが暴走して毎秒何度もログを出力することがあります。例えば、サスペンドからの復帰後のamdgpuのバグなどです。それをフィルタリングするのに時間がかかりましたが、幸いにもカーネルメッセージ(dmesg)だったので可能でしたが、しばらくの間、永続的なカーネルログを無効にしなければならず、それは理想的とは言えませんでした。
特定のコア部分では単純さが機能よりも重要であることは理解しています。しかし、journaldは永続ストレージを有効にするにはあまりにも基本的すぎますが、オフにしたいわけでもありません。
- barrkel
journaldは私の意見ではsystemdエコシステムの中で最悪の部分です。ルーターとしてのみ使用し、ログを保存しない方が良いでしょう。それが使用するインデックスシステムは遅く、おしゃべりなサブシステムを制御できません - 単一の識別子のログだけを切り詰めることはできません。インデックスが行っているすべての用途に対して、agやrgのような最新のgrepの方がパフォーマンスが良いでしょう。構造には価値がありますが、それはjournald以外の場所にある方が良いです。
- smartmic
私は最近journaldのディスク使用量を調べて、ショックを受けました。私の次の平穏へのステップはhttps://www.devuan.org/os/init-freedomです。
Debianシステムの次のディストリビューションとして試してみます。別のマシンでのVoid Linux(runit)の長年の経験は素晴らしいです。
- ValdikSS
https://github.com/systemd/systemd/issues/40262#issuecomment...