こんにちは。サイオステクノロジー OSS サポート担当の山本です。
ある日、障害調査を行なっている時に、/var/log/sa/sarXX 内の %commit という項目が 100 を超えた値になっていることに気づきました。「% のはずなのに 100 を超えている?」と首をかしげつつ、この値について確認してみることにしました。
■%commit とはどんな値か。
まず、%commit の記録されている /var/log/sa/sarXX ファイルについてですが、システムの統計情報に関連する機能が集まった sysstat パッケージに含まれている機能・コマンドの一つである、sar で出力されたファイルになります。CPU やメモリ、I/O や各種デバイスやネットワークなど、システムに関連する様々な利用状況の情報を定期的に記録しているもので、システムの動作状況を確認する際に非常に便利な代物です。
ということで早速 man sar を確認してみると、%commit について以下のような説明がありました。
%commit Percentage of memory needed for current workload in relation to the total amount of memory (RAM+swap). This number may be greater than 100% because the kernel usually overcommits memory.
「現在のワークロードで要求されている総メモリ量の割合。カーネルはメモリのオーバーコミットをするため、100% を超える可能性がある」とのことです。なるほど、100% を超えているのはバグの類ではなさそうです。
■メモリのオーバーコミットとは?
Linux においては、プロセスがメモリを確保する場合、即座に実際のメモリを割り当てるのではなく「仮想メモリ」のみを割り当てます。そして、実際に使用する段になって初めて実際の物理メモリを割り当てます。
何故そのようなことをするのかというと、「プロセスが要求するメモリは実際に全て使われることはあまりないから」とされています。
例えば、「ピーク時には 40MB ほどメモリを使用するので、とりあえず 40MB メモリ確保する」というプログラムがあったとします。しかし、このプログラムが実際に 40MB ものメモリを使用することは殆どなく、普段は多くても 1MB くらいしかメモリを消費しないものかもしれません。この場合、要求された分のメモリを常に割り当てる仕組みになっていると、このプログラムが動作している間は 39MB ものあまり使われないメモリが割り当てられたままになってしまいます。
このように、プログラムやプロセスに要求された分だけメモリを渡してしまうと、実際に使用されることなく確保され続けるメモリが出てきてしまう可能性があります。そうなると、こういった「確保はされているものの使われていないメモリ」を使用できれば動くかもしれない別のプロセスが動かせなくなるなど、システムの動作に悪影響が出てしまう可能性が考えられます。
そのため、Linux では先述のとおり、「要求されたメモリをそのまま渡さず、実際に使用する際に必要な分だけメモリを割り当てる」というアプローチを取ります。例え要求されたメモリの総量が実際のメモリより多くなろうと、実際にメモリ不足に陥るまでは「ま、実際には使ってないし平気平気!」と、どんどんプログラム等の動作を許可してしまいます。結果、「要求メモリ量の総量 = %commit」が 100% を超えてしまうことがあるのです。
このように、実際のメモリ総量を超えたメモリ要求を許可する動作を「オーバーコミット」と呼びます。おかげで Linux ではメモリを無駄なく活用することができるのです。
しかし、ちょっと待ってください。こうやって動作させたプロセスたちが実際に大量のメモリを使用しはじめ、実際のメモリの使用量がシステムの限界を超えそうになってしまったらどうなってしまうのでしょう?
その答えは、「重要度が低そう」「動作していなさそう」「メモリの使用量が多そう」などの条件から考えていらなそうなプロセスを殺して、そのプロセスが使っていたメモリから確保する……そう、あの「OOM-killer」によってこの問題が解決されているのです。何かと障害の原因と扱われたり恨まれたりしている OOM-killer ですが、このオーバーコミットを利用して効率よくメモリを運用するためには不可欠なものなのです。
■オーバーコミットを調整する
オーバーコミットによってメモリが無駄なく利用できる、その際に実際のメモリ使用量が破綻しないように OOM-killer が働いてくれる。理屈はわかるけど、それでもやっぱり OOM-killer は憎いし怖いし嫌いなのでやって来て欲しくない!!…ということもあるでしょう。そういった場合には、オーバーコミットが可能な量を制御する設定がきちんとあります。
/etc/sysctl.d/ 配下の設定ファイルに以下の設定を記述します。その後に再起動、または “sysctl -p” コマンドを実行することで設定が有効になります。
vm.overcommit_memory = X
X には 0 ~ 2 の値が設定でき、それぞれ以下のような設定になります。
0:ヒューリスティック (デフォルト)
「その時点で実際に利用可能なメモリ総量」を超えるメモリの要求を拒否します。程よい感じになるようにオーバーコミットを許可する設定です。
1:無制限
オーバーコミットの制御を行いません。どれだけのサイズのメモリの要求も通ります。OOM-killer の発生リスクは高まりますがメモリの要求が阻害されないため、メモリの使用量が多いプロセスのパフォーマンスが向上する可能性があります。
2:無効
要求されているメモリの総量が “[swap の総量] + [物理メモリ総量 * vm.overcommit_ratio/100]” を超える場合、メモリの要求を拒否します。OOM-killer の発生リスクは低いですが、メモリの要求できる量が制限されるため、swap 領域が物理メモリよりも大きく十分なサイズであるシステム以外では推奨されません。
(※vm.overcommit_ratio も /etc/sysctl.d/ 配下の設定ファイルに設定を記述できます。デフォルトは 50 です。)
なお、現時点での設定値は “sysctl vm.overcommit_memory” コマンドを実行すると確認することができます。見てのとおり、vm.overcommit_memory = 2 を設定すれば OOM-killer の発生率は下げられる…はずです。ただ、逆にメモリが確保できずにプロセスを動かせないといったことが起こる可能性もありますので、変更するのであればまず他にメモリ関連の問題がないかを確認してから、システムの性格を考えた上で変更するのがよいと思います。
■最後に
以上、「%commit とオーバーコミット」のお話でした。
実際に %commit は 100 を超えることがあるとは言えど、%commit が 100 を超えている状態はメモリが不足する可能性がある状態と読み替えることもできますので、頻繁に 100 を大きく超えている場合には何か原因がないかを探っておくと事前にトラブルを回避することができるかもしれません。また、常時 100 を大きく超えている場合は、単純なメモリ不足やメモリリークの可能性も考えられます。
今回は %commit についてのみのお話でしたが、sar の観察はマシンの異常の原因を探る重要な糸口となることがありますので、上手く活用していきたいものです。