2014-06-14

Linuxにおけるメモリ管理

DBサーバ上でおもむろにfree、sar、topコマンド等でメモリの使用率を見てみたところ、 メモリの空きがほとんど無くなっていることに気がついて(正確にはそう見えて)、焦りながら色々調べた結果をまとめる。

Linuxのページキャッシュの仕組み

まず、メモリの使用率を正しく見るためには、Linuxのページキャッシュという機能について知らないといけなかった。

ページキャッシュとは

Linuxは一度ディスクから読みだしたデータは可能な限りメモリにキャッシュして、次回以降の読み込みが高速に行われるように調整する。このメモリに読みだしたデータのキャッシュを「ページキャッシュ」と呼ぶ。
※ CPUはディスクのデータを直接読むことができないので、一度ディスクのデータをメモリにロードしてから読み込んでる

ちなみに、Linuxはメモリ領域を4KBの塊に区切って管理しており、この4KBの塊を「ページ」という。

Linuxにおけるページキャッシュ

そして、 Linuxは可能な限り空いているメモリをページキャッシュに回そうとする というポリシーは必ず覚えておく必要がある。
具体的には以下のフローを辿ることになる。

  1. 何かディスクからデータを読んで、
  2. まだそれがページキャッシュ上になく、
  3. かつメモリが空いていれば、
  4. (古いキャッシュと入れ替えるのではなく)いつでも新しいキャッシュを構築する
  5. キャッシュ用のメモリが空いていなければ、古いキャッシュを捨てて新しいキャッシュと入れ替える。

このようなポリシーがあるため、Linuxのメモリ使用率は時間を追うごとに増えていくことになる。
sar -rコマンドで見た場合、時間の経過とともにkbmemfreeが減っていき、kbcachedが増えていく。

ディスクからデータを読み取るというのは、ページキャッシュを構築することに他ならない。
つまりDBのようにディスクに保存されているデータを扱うサーバであれば、すぐにメモリの使用率は上がっていく。

ここらへんの知識があるだけで、各コマンドの結果を冷静に見ることができるようになった。

利用可能なメモリの量を見極める

ページキャッシュを捨てるためにはストレージとの同期が必要

ページキャッシュは新たなストレージデータの読み出し・書き出し要求等があってメモリが必要にならない限り、メモリを解放しない。
しかし、ページキャッシュはストレージとの同期が取れていさえすれば、すぐに捨てることが可能である。
ストレージとの同期がとれていない状態だと捨てることができないが、この同期作業は定期的に行われているため時間が経てば捨てることは可能になる。

freeコマンドでメモリ使用率を見る

freeコマンドを実行すると、以下のような結果が出てくる(このデータは自分のPCの仮想環境で行った結果)。

$ free
             total       used       free     shared    buffers     cached
Mem:        501800     361164     140636        652      54768     167740
-/+ buffers/cache:     138656     363144
Swap:            0          0          0

最初、自分はMem行のfreeの値を見て全体の数%しか空いていなかったので、焦った。
実際は、「-/+ buffers/cahce」行のfreeの値がページキャッシュを空き容量として換算したメモリの空き容量なので、メモリの空き容量を見るときは、ここを確認するのが正しい。
しかし、「-/+ buffers/cahce」行のfreeの値にはストレージと同期されていないページキャッシュも含んでいるため、実際に利用可能なメモリを把握するにはこれでは不十分。

vmstatコマンドでストレージとの同期がとれたページキャッシュを把握する

これまでの情報を整理すると、実際に利用可能なメモリを把握するには、「ストレージとの同期がとれたページキャッシュを空き容量と見なしたメモリ使用率」を把握する必要があることになる。

この情報を確認するにはvmstatコマンドを使う。

$ vmstat -a
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free  inact active   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 140492 152692 148976    0    0    11    32   11   19  0  0 100  0  0

上のうち、activeの値はキャッシュや無名ページのうち、まだストレージとの同期がとれていない「捨てられない」ページ。 一方、inactはキャッシュや無名ページのうち、すぐに捨てることができるページ。

なので、freeコマンドで確認したMem行のfreeとvmstat -aコマンドで確認したinactが実際に利用可能なメモリ量になる。 この値を全体のメモリ量で割れば、使用率が見えてくる。

スワップ

使用率だけでなく、スワップについても確認したほうが良さそうなので一から調べた。

スワップとは

スワップとは、ハードディスクなどの補助記憶装置を利用して使用可能なメモリ容量を増やすOSの機能。
ハードディスク上に「スワップ領域」と呼ばれる専用の領域を用意して、メモリ容量が不足してきたら現在使われていないプログラムを一時的にスワップ領域に退避させ、占有していたメモリを開放する。 スワップ領域に対比された内容に、プロセスからアクセスが発生すると再度メモリ上に読み込まれる。

メモリからスワップ領域に退避する動作を「スワップアウト」、スワップ領域からメモリに書き戻す動作を「スワップイン」と呼ぶ。

長時間アクセスされないメモリ上のデータは、スワップ領域に移動することで物理メモリを効率的に使用できるので、スワップアウトが発生すること自体は問題ではない。
一方、スワップアウトと同時にスワップインが頻繁に発生する場合は、頻繁にアクセスされるデータがスワップアウトされており、スワップ領域へのアクセスによるパフォーマンスの低下が予想される。

スワップの動作を確認する

スワップアウトとスワップインが頻発している状態は本当にメモリが不足している状況と言える。
スワップの動作状況はvmstatとsarコマンドで確認することができる。
リアルタイムに見たい場合はvmstat、過去の情報を遡りたいときはsar -Wで確認する。

$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  0      0 140384  54984 167816    0    0    10    29   11   18  0  0 100  0  0
 0  0      0 140372  54984 167816    0    0     0     4   14   18  0  0 100  0  0
 0  0      0 140372  54984 167816    0    0     0     0   13   19  0  0 100  0  0
 0  0      0 140372  54984 167816    0    0     0     0   10   12  0  0 100  0  0
 0  0      0 140372  54984 167816    0    0     0     0   21   31  0  0 100  0  0
 .
 .
 .

vmstatの場合は、siとsoのところを見る。
一時的なものであれば問題無いが、頻繁にsiとsoが動いていないかを確認する。

$ sar -W
Linux 3.13.0-29-generic (vagrant-ubuntu-trusty-64)      06/14/2014      _x86_64_        (1 CPU)

03:45:02 AM  pswpin/s pswpout/s
03:55:01 AM      0.00      0.00
04:05:01 AM      0.00      0.00
04:15:01 AM      0.00      0.00
04:25:01 AM      0.00      0.00
04:35:01 AM      0.00      0.00
.
.
.

sar -Wのpswpinは1秒間にスワップインしているページ数でpswpoutは1秒間にスワップアウトしているページ数。

以上を踏まえて再度メモリ使用率を確認してみたところ、実際に利用できるメモリは40%以上あったので問題無いと判断できた。

メモリとディスクの速度差

メモリはディスクの10の5乗から10の6乗倍(10万倍〜100万倍)以上、高速に探索することができる。
メモリ内で計算することができれば、多少力技でやっても高速に読み取りが可能であるため、大規模なサービスになると如何にしてディスクではなくメモリにデータを載せるかが重要になってくる。

なぜここまで速度差があるのかというと、電気的な部品であるメモリは物理的な構造に探索速度が左右されないのに対して、ディスクは円盤からヘッドを使ってデータを読み取るという物理的な動作が伴うからである。
ディスクは、ヘッダを動かす時間やディスクを回転させる時間など、もろもろの物理的動作を経て探索をしなければならない。

sar -r コマンドの見方

あんまり使わなかったけど、一応メモ。

項目名 説明
kbmemfree 物理メモリの空き容量
kbmemused 使用中の物理メモリ量
memused 物理メモリ使用率
kbbuffers カーネル内のバッファとして使用されている物理メモリの容量
kbcached カーネル内のキャッシュ用メモリとして使用されている物理メモリの容量
kbswapfree スワップ領域の空き容量
kbswpused 使用中のスワップ領域の容量

参考