先日のこの話 、Out Of Memory Killer 、通称OOM Killerのせいらしい。キャッシュとしてshared memoryを贅沢に(^^;)使用するPostgresSQLのWrite processが集中的に狙われてます>_<。
直接的にこの仕組みを切るにはかecho 0 > /proc/sys/vm/oom-kill
ただし前者はRedHat独自&OOM Killer完全停止、後者はカーネル2.6.11以降&プロセスごとに設定。CentOS 4.4のカーネルは現時点2.6.9なので前者。もうひとつの方法として、OOM Killerが発動する1つの原因を作っているメモリのオーバーコミットをさせない方法。具体的には、echo -17 > /proc/(PID)/oom_adj
これを起動時に自動設定させるには、/etc/sysctl.confに以下の行を追加。echo 2 > /proc/sys/vm/overcommit_memory
echo 90 > /proc/sys/vm/overcommit_ratio
vm.overcommit_memory = 2
vm.overcommit_ratio = 90
ちなみにオーバーコミットとは何かといいますと、「ありもしないメモリを割り当てる」こと。全てのプログラムは情報を記録するためのメモリが必要で、必要な量をOSに事前申請(malloc)して割り当ててもらう必要があります。最近のJavaとか.NET使っている方はそんなのやったことないかもしれませんが、それはJava runtimeや.NET Frameworkが自動でやってくれているからです。後で追加申請できますが、プログラムが複雑になりやすいので最初に多めに申請する場合が多いです。
従来のOSは申請に応じてマシンのメモリを分け与え、無くなったら以後の申請は却下するわけですが、前述のように使わないのに多めに申請するプログラムが多いと(いや、実際に多いw)、有効利用されないメモリが多くなって効率が悪い。
そこで「どうせお前ら、使いもしないのに多めに申請してるんだろ!?」と考えるLinuxは(w)、事前申請は気前良くと受け付けます。たとえマシンにそれだけメモリがなくても。仮想メモリを自動的に増やすという話じゃありません。実メモリ+仮想メモリの合計以上に申請されても許可しちゃうんです。で、各プログラムが実際にメモリを使おうとしたときに初めて使う分だけ本物のメモリを分け与えるわけです。(これだけでも、私には良くそんな面倒なもの作ったなと感心)
問題はもし多くのプログラムが申請した分のメモリを本当に使い出したら・・・。足りません。どうせ実際には使いやしないと高をくくって申請は受けましたが、無いものは無いのです。しかしプログラムはそのメモリにアクセスできないとそれ以上処理できないわけで。他のプログラムが終わってメモリが返却されるのを悠長に待ってはいられない場合もあるでしょう。さて、どうするか? 「しょうがねぇ、いくつかのプログラムお取り潰しにして、そこが使っていたメモリを巻き上げるか・・・」そこでOOM Killerです。
メモリが少ないから何も言わず終了してくれ(会社の経営が苦しいから、何も言わずに辞めてくれw)、ってOSからご丁寧に頼んで素直に聞いてくれるプログラムばかりなら良いですが、事は一刻を争う。OOM Killerによるお取り潰しはプログラムに了解無く一方的に行われます。ただ無作為にプログラムを止めるわけではなく、大切なプログラムは見逃すとか独自のルールを持ってます。それに照らし合わせるとメモリを大量消費しているPostgreSQLのwriterが目を付けられると。
上の対策は分け与えるメモリが無いなら申請時に却下するという、従来のメモリ管理にすることになります。メモリの利用効率が悪くなってしまいますが、OOM Killerの出番がなくなります。
参考なんかこれ・・・メモリの先物取引とか手形に思えるのは、私だけでしょうか? OSがこんな実装するなんて、ちょっと意外。
Comments