メモリとOOMの診断
目標
メモリのメトリクスを正確に読み取り、プロセスが実際に握ったメモリと予約しただけのアドレス空間を区別し、OOM Killerが何を見て選ぶのかを確認します。
なぜ重要なのか
メモリ問題の誤診の大半は、間違った列を見ることから始まります。freeのfree列ではなくavailable列を見る必要があり、topのVIRTではなくRES(RSS)を見る必要があります。OOM Killerのスコアも、RSS基準です。64GBをmmapで予約しただけのプロセスは、候補にすらなりません。そしてコンテナの中でfreeはホスト全体を表示するため、本当の上限はcgroupのファイルから読み取る必要があります。このラボのステップ7が「なければないと書く」ことまで採点する理由は、現場でもそのファイルがあるかどうかを確認することが最初の動作だからです。
ステップ
/root/memディレクトリで作業します。
/proc/meminfoのMemTotalの値を、kBの数字だけ/root/mem/total_kb.txtに書いてください。MemAvailableの値を、kBの数字だけ/root/mem/available_kb.txtに書いてください。- 実際の常駐メモリ(VmRSS)が100MB以上のプロセスをバックグラウンドで起動し、PIDを
/root/mem/hog_pid.txtに書いてください。以降のステップの間ずっと生きている必要があります。 - そのプロセスの
VmSizeとVmRSSを、/root/mem/vm.txtに次の2行で書いてください(プレースホルダーは値です)。vsize_kb=<값>rss_kb=<값>
- そのプロセスの
oom_score_adjを500に設定し、その後に読み取ったoom_scoreの値を/root/mem/oom_score.txtに書いてください。 /root/mem/topmem.sh <N>を作成してください。RSS上位N個のプロセスを<rss_kb> <comm>の形式で、降順に出力します。ちょうどN行である必要があります。- このコンテナのcgroupメモリ制限を、
/root/mem/limit.txtにそのまま書いてください。該当ファイルを読み取れない環境なら、unavailableと書いてください。 /root/mem/memguard.sh <임계값kB>を作成してください(プレースホルダーはしきい値のkBです)。RSSがしきい値を超えるプロセスがあれば、over=<PID>を1行ずつ出力して終了コード1、なければokを1行出力して終了コード0です。引数がなければ、0以外のコードで終了します。
参考
python3 -c "import time; b=bytearray(150*1024*1024); time.sleep(9999)" &で、メモリを実際に握らせることができます。/proc/<PID>/statusにはVmSizeとVmRSSが、/proc/<PID>/oom_scoreとoom_score_adjがそれぞれあります。- カーネルスレッドには
VmRSSの項目がないため、ステップ6とステップ8で除外する必要があります。 - よくあるミス1: ステップ3でメモリを割り当てるだけで使わないと、VmSizeだけが増えて、VmRSSはそのままです。
- よくあるミス2: ステップ5で
oom_scoreを先に読み、adjをあとで変えると、値が合いません。
メモリ全体を読み取る
/proc/meminfoのMemTotalの値を、kBの数字だけ/root/mem/total_kb.txtに書いてください。
/proc/meminfoの最初の項目です。単位はkBのまま、数字だけを書いてください。
MemAvailableとMemFreeを区別する
MemAvailableの値を、kBの数字だけ/root/mem/available_kb.txtに書いてください。
Linuxは余ったメモリをページキャッシュとして使います。回収可能な量まで計算した値が別にあります。
メモリを実際に握る
実際の常駐メモリ(VmRSS)が100MB以上のプロセスをバックグラウンドで起動し、PIDを/root/mem/hog_pid.txtに書いてください。以降のステップの間ずっと生きている必要があります。
割り当てるだけで触れなければ、RSSは増えません。実際に埋める必要があります。python3でbytearrayを作って、sleepすればよいです。
VmSizeとVmRSSの比較
そのプロセスのVmSizeとVmRSSを、/root/mem/vm.txtに次の2行で書いてください(プレースホルダーは値です)。
vsize_kb=<값>rss_kb=<값>
/proc//statusに両方あります。予約されたアドレス空間と実際の常駐メモリの違いを確認してください。
OOMスコアを調整する
そのプロセスのoom_score_adjを500に設定し、その後に読み取ったoom_scoreの値を/root/mem/oom_score.txtに書いてください。
/proc//oom_score_adjに値を書けばよいです。上げることは常に許可されています。変更したあとにoom_scoreを読み取ってください。
RSS上位のプロセスを取り出す
/root/mem/topmem.sh <N>を作成してください。RSS上位N個のプロセスを<rss_kb> <comm>の形式で、降順に出力します。ちょうどN行である必要があります。
/proc/*/statusのVmRSSを集めて、並べ替えます。カーネルスレッドにはVmRSSの項目がありません。
コンテナの本当の制限を探す
このコンテナのcgroupメモリ制限を、/root/mem/limit.txtにそのまま書いてください。該当ファイルを読み取れない環境なら、unavailableと書いてください。
freeコマンドはホストを表示します。実際の上限はcgroupのファイルにあります。なければないと書いてください。
メモリ監視スクリプト
/root/mem/memguard.sh <임계값kB>を作成してください(プレースホルダーはしきい値のkBです)。RSSがしきい値を超えるプロセスがあれば、over=<PID>を1行ずつ出力して終了コード1、なければokを1行出力して終了コード0です。引数がなければ、0以外のコードで終了します。
しきい値を引数として受け取り、超過しているプロセスを報告します。超過があれば終了コード1、なければokと0です。