Linux のオーバーコミットについて調べてみた
Linux のオーバーコミットのはなし
(これを書いたのは Linux 2.6.38 のとき)
Linux カーネルは実メモリ以上にメモリをプロセスに割り当てることができる
この仕組みをオーバーコミット (over-commit) と呼ぶ
オーバーコミットでは,とりあえずメモリを malloc
させて仮のアドレスを返しておき,
実際に使われる段になってはじめて実メモリを確保する.
実験
ただ malloc
し続けるだけのプログラムを作って実験してみる.
このプログラムをメモリ 1 GB + スワップ 1 GB のホストで実行してみると,
$ free -t
total used free shared buffers cached
Mem: 1022404 82992 939412 0 4172 12280
-/+ buffers/cache: 66540 955864
Swap: 1044476 0 1044476
Total: 2066880 82992 1983888
$ gcc -o oc_test oc_test.c
$ ./oc_test
76152GB
76152GB = 74TB も malloc
できた計算になる.つまり,Linux では
(オーバーコミットできるメモリの大きさ)>(実際に利用可能なメモリの大きさ)
となる.
しかし,オーバーコミットしたメモリは実際には存在しないので,
いつかはメモリが足りなくなるときが来る.そんなときはどうするのか.
何のことはない,カーネルが OOM killer (out of memory killer)
というロシアンルーレットを回して,
メモリが空くまで手当たり次第にプロセスを殺していくのである.
ただし,カーネルスレッドとか init
とかは殺さないし,また,
sshd
のようにディストリビューションのデフォルトで
oom_score
が 0 に設定されるプロセスも
OOM killer の対象外となる.(oom_score
については後述)
試しに実際に利用可能な量を越えて, オーバーコミットしたメモリを使おうとすると
$ ./oom_killer_test
Killed
と OOM killer がやってきて殺される.
この場合は犯人の oom_killer_test
が殺されたが,
OOM killer は犯人以外のプロセスを殺すこともある.
それゆえ,先に「ロシアンルーレット」という表現を使ったのである.
OOM killer が殺すプロセスを決定するルールは,
http://www.kernel.org/doc/Documentation/vm/overcommit-accounting
に詳しい.
オーバーコミットの設定
OOM killer が発動すると,犯人以外のプロセスが殺されることもある, と先に述べた.言い換えると OOM killer が無実の重要なプロセスを殺すかも しれないということである.これでは困るので, 重要なプロセスが走っているホストではオーバーコミットを無効にすることがある.
オーバーコミットの有効・無効を切り替えるには,
sysctl vm.overcommit_memory
を設定する.
vm.overcommit_memory
の値は,
- 0
- オーバーコミット有効
- 一回の
malloc
で確保できるのは実際に利用可能なメモリの大きさまで
- 1
- どんなときでもオーバーコミット可
- 一回の
malloc
で実際に利用可能なメモリを越える大きさでも確保可能
- 2
- オーバーコミット無効
malloc
で割り当てられるメモリの総量は (スワップの大きさ)+(物理メモリの大きさ)*vm.overcommit_ratio / 100
なので,OOM killer を避けたいときには
vm.overcommit_memory=2
を /etc/sysctl.conf に追加して,sysctl -p
すればよい.
ただし,オーバーコミットを無くせば out of memory が無くなるというわけ
ではないので,vm.overcommit_memory=2
しても,OOM killer
を完全には止められない.どうしても死んで欲しくないプロセスには,
oom_adj
を設定しよう.これは,OOM killer に殺される
確率を調整するパラメータで,-17
にすると OOM killer の対象外になる.
process_id の oom_adj
を
$ sudo echo -17 > /proc/864/oom_adj
すると,
$ cat /proc/864/oom_score
0
ここで,864
はプロセス id である.
OOM killer が発動する前にリブートさせる戦略
OOM killer が発動すると重要なプロセスを殺してしまい, システムが不安定になるかもしれない. そもそも,OOM killer が発動する状況では, メモリなどのリソースが不足していると想定されるので, そのままシステムを稼動させていると,いつ不安定になるか分からない.
そこで,OOM killer が発動するようなメモリが不足する状況になったら,
システムをリブートしてしまうという戦略をとることがある.
この戦略を実現するためには,まず sysctl
で,
vm.panic_on_oom
に 1 を設定して
OOM 時にカーネルパニックになるようにする.そして,
kernel.panic
に適当な秒数を設定し,
カーネルパニックが起きたら自動でリブートするよう設定する.
$ sudo sysctl -w vm.panic_on_oom=1
$ sudo sysctl -w kernel.panic=60
この例では OOM →即,カーネルパニック→ 60 秒後再起動となるよう設定している.
おすすめ設定
(守備的な設定)
システムが不安定になるのを避けたいときは,
オーバーコミットを無効にするのがよい.
加えて,重要なプロセスには oom_adj=-17
して,
OOM killer の対象外となるようにする.
$ sudo sysctl -w vm.overcommit_memory=2
$ sudo echo -17 > /proc/864/oom_adj
この設定の場合,利用できるメモリは実際の物理メモリと比べて少なくなる.
デフォルトでは vm.overcommit_ratio
が 50 なので,
全プロセスが利用できるメモリは物理メモリの 50% となる.
(残りはカーネルがおいしく頂くことになる)
(攻撃的な設定)
システムが不安定になるリスクと引き換えにメモリを目一杯使いたいときは, オーバーコミットを無制限にして, メモリが足りなくなったら潔く再起動すればよい.
$ sudo sysctl -w vm.overcommit_memory=1
$ sudo sysctl -w vm.panic_on_oom=1
$ sudo sysctl -w kernel.panic=60
おわりに
Linux のオーバーコミットについて調べたことをまとめてみた. メモリをたくさん使うジョブを走らせているホストが不安定になったら, それは,OOM killer のせいかもしれない.そんなときには, オーバーコミットの設定を変更することを考えてみよう.
12 Notes/ Hide
- uokada liked this
- sibukixxx reblogged this from passingloop
- kysnm liked this
- tropicalsanta liked this
- passingloop posted this