過去数か月間、Linuxシステムで非常に苛立たしい問題が発生しました。Firefoxのオーディオ再生やマウスの動きなどで途切れ、数秒ごとにわずか1秒未満(ただし目立つ)のスタッターが発生します。この問題は、メモリキャッシュがいっぱいになるか、ディスク/メモリを大量に消費するプログラム(バックアップソフトウェアrestic
など)を実行しているときに悪化します。ただし、キャッシュがいっぱいでない場合(たとえば、非常に軽い負荷の場合)、すべてが非常にスムーズに実行されます。
perf top
の出力を見ると、これらのラグの期間中、list_lru_count_one
のオーバーヘッドが高い(〜20%)ことがわかります。 htop
は、50〜90%のCPUを使用するkswapd0
も示しています(ただし、影響はそれよりはるかに大きいように感じます)。極端な遅延の時間帯には、htop
CPUメーターはカーネルのCPU使用率によって支配されることがよくあります。
私が見つけた唯一の回避策は、カーネルに空きメモリ(sysctl -w vm.min_free_kbytes=1024000
)を保持させるか、echo 3 > /proc/sys/vm/drop_caches
を介してメモリキャッシュを継続的に削除することです。もちろん、どちらも理想的ではなく、吃音を完全に解決するものでもありません。頻度が減るだけです。
なぜこれが起こっているのかについて誰かが何か考えを持っていますか?
-ck
パッチセットの使用(役に立たなかった)[〜#〜] edit [〜#〜]:わかりやすくするために、htop
とperf
の写真を次に示します。そのようなラグスパイクの間に。高いlist_lru_count_one
CPU負荷とkswapd0
+高いカーネルCPU使用率に注意してください。
問題が見つかりました!
コンテナ/メモリcgroupが多数ある場合、Linuxのメモリリクレーマのパフォーマンスの問題であることが判明しました。 (免責事項:私の説明には欠陥がある可能性があります。私はカーネル開発者ではありません。)この問題は4.19-rc1 +で修正されました このパッチセット :
このパッチセットは、多くのシュリンクとメモリcgroupを備えた(つまり、多くのコンテナを備えた)マシンで発生するshrink_slab()が遅いという問題を解決します。問題は、shrink_slab()の複雑さがO(n ^ 2)であり、コンテナー数の増加に伴って急速に増加することです。
200個のコンテナーがあり、すべてのコンテナーに10個のマウントと10個のcgroupがあるとします。すべてのコンテナタスクは分離されており、外部コンテナのマウントには触れません。
グローバルリクレイムの場合、タスクはmemcgs全体を反復処理し、すべてのmemcg対応シュリンクを呼び出す必要があります。つまり、タスクはmemcgごとに200 * 10 = 2000のシュリンクを訪問する必要があり、2000 memcgsがあるため、do_shrink_slab()の合計呼び出しは2000 * 2000 = 4000000になります。
かなりの数のコンテナーを実行しているため、システムが特に大きな打撃を受けました。これが問題の原因である可能性があります。
同様の問題に直面している人に役立つ場合のトラブルシューティング手順:
kswapd0
が大量のCPUを使用していることに注意してくださいftrace
(以下 Julia Evanのすばらしい説明ブログ )を実行してトレースを取得します。kswapd0
がshrink_slab
、super_cache_count
でスタックする傾向があることを確認してください。 、およびlist_lru_count_one
。shrink_slab lru slow
、パッチセットを見つけてください!私が最初に提案したであろう多くのこと(スワップ構成の調整、I/Oスケジューラーの変更など)をすでに試したようです。
すでに変更を試みたものとは別に、VMライトバック動作のやや脳死したデフォルトを変更することを検討することをお勧めします。これは、次の6つのsysctl値によって管理されます。
vm.dirty_ratio
:ライトバックがトリガーされる前に、ライトバックを保留する必要がある書き込みの量を制御します。フォアグラウンド(プロセスごと)のライトバックを処理し、RAMの整数パーセントとして表されます。デフォルトはRAMの10%vm.dirty_background_ratio
:ライトバックがトリガーされる前に、ライトバックを保留する必要がある書き込みの量を制御します。バックグラウンド(システム全体)のライトバックを処理し、RAMの整数パーセントとして表されます。デフォルトはRAMの20%vm.dirty_bytes
:合計バイト数で表されることを除いて、vm.dirty_ratio
と同じです。このまたはvm.dirty_ratio
のいずれか、最後に書き込まれた方が使用されます。vm.dirty_background_bytes
:合計バイト数で表されることを除いて、vm.dirty_background_ratio
と同じです。このまたはvm.dirty_background_ratio
のいずれか、最後に書き込まれた方が使用されます。vm.dirty_expire_centisecs
:上記の4つのsysctl値がまだトリガーしていない場合に、保留中のライトバックが開始するまでに100分の1秒が経過する必要があります。デフォルトは100(1秒)です。vm.dirty_writeback_centisecs
:カーネルがダーティページのライトバックを評価する頻度(100分の1秒単位)。デフォルトは10(10分の1秒)です。したがって、デフォルト値では、10分の1秒ごとに、カーネルは次のことを行います。
したがって、システムが最大4ギガバイトを書き出そうとしている可能性があるため、デフォルト値が問題を引き起こしている理由を簡単に理解できるはずです。 )データの永続ストレージへの10分の1秒ごと。
最近の一般的なコンセンサスは、vm.dirty_ratio
をRAMの1%に調整し、vm.dirty_background_ratio
を2%に調整することです。これは、約64GB未満のシステムの場合RAMその結果、当初の意図と同等の動作が得られます。
調べるべき他のいくつかの事柄:
vm.vfs_cache_pressure
sysctlを少し増やしてみてください。これは、RAMが必要なときにカーネルがファイルシステムキャッシュからメモリをどれだけ積極的に再利用するかを制御します。デフォルトは100ですが、50未満に下げないでください(OOM条件を含め、50未満にすると、は非常に悪い動作になります)、そして、それを約200をはるかに超えて上げないでください(はるかに高くなると、カーネルは実際にはできないメモリを再利用しようとして時間を浪費します)。適度に高速なストレージがある場合は、150まで上げると、実際に応答性が目に見えて向上することがわかりました。vm.overcommit_memory
sysctlの値を変更することで実行できます。デフォルトでは、カーネルはヒューリスティックアプローチを使用して、実際にコミットできるRAM)の量を予測しようとします。これを1に設定すると、ヒューリスティックが無効になり、カーネルに無限大のように動作するように指示されます。これを2に設定すると、カーネルは、システム上のスワップスペースの合計量に実際のRAM(vm.overcommit_ratio
によって制御される)のパーセンテージを加えたものより多くのメモリにコミットしないようになります。vm.page-cluster
sysctlを微調整してみてください。これは、一度にスワップインまたはスワップアウトされるページ数を制御します(これは基数2の対数値であるため、デフォルトの3は8ページに変換されます)。実際にスワップしている場合、これはページのスワップインとスワップアウトのパフォーマンスを向上させるのに役立ちます。