ハードウェア基礎 #3 メモリ — RAM と階層構造、スワップが始まると起きること

読了 7分

#2 で、CPU はメモリを待つ時間を減らすためにキャッシュを置くと述べました。その待ち相手が今回の主題であるメモリです。メモリは普段は静かで、足りなくなる瞬間にシステム全体を崖の下へ落とします。その動作を理解すれば、「メモリ使用率が高いけれど大丈夫か」のような問いに測定で答えられるようになります。

ハードウェア基礎 シリーズでの今回の位置です。

RAM とは何か #

RAM (Random Access Memory) は CPU がいま使うデータを置く作業空間です。プログラムを実行すると、そのコードとデータがストレージから RAM へ上がり、CPU は RAM に上がったものを読み書きします。

RAM には 2 つの重要な性質があります。

  • 揮発性 — 電源が切れると中身が消えます。だから永続保管はストレージが担います。
  • ランダムアクセス — どの位置でもほぼ同じ速度で読みます。順番に辿らないと速くない一部のストレージと違う点です。

核心は単純です。RAM は速いものの限られていて、電源が切れると中身が消える一時的な作業空間です。

メモリ階層 #

コンピュータの保存空間は 1 つではなく複数の層です。上に行くほど速く小さく高価で、下に行くほど遅く大きく安いです。

おおよそのアクセス時間サイズ揮発性
レジスタ1ns 未満数百バイト揮発性
L1 キャッシュ約 1ns数十 KB揮発性
L2 / L3 キャッシュ数 ns ~ 数十 ns数 MB揮発性
RAM約 100ns数 GB ~ 数百 GB揮発性
SSD / NVMe数十 ~ 数百 μs数百 GB ~ 数 TB不揮発性
HDD数 ms数 TB不揮発性

単位が 1 行下りるたびに大きく跳ねる点に注目します。RAM は約 100ns、SSD はそれより数百倍、HDD は数万倍遅いです。

差を体感する — RAM アクセスを 1 秒に換算すると
RAM アクセス   100ns   →  1 秒
SSD アクセス   100μs   →  約 17 分
HDD アクセス   10ms    →  約 28 時間

この差が次の節の核心です。データが RAM にあるときと、ディスクまで下りなければならないときの違いがそれほど大きいのです。

容量・帯域幅・レイテンシは別の軸 #

メモリを語るとき 3 つがよく一緒くたにされます。区別しておくとスペック表が違って読めます。

意味足りないと
容量一度に置ける量 (GiB)スワップが始まる
帯域幅1 秒に運べる量 (GB/s)大量処理で滞る
レイテンシ1 回のアクセスにかかる時間 (ns)頻繁なランダムアクセスで遅くなる

運用でもっともよくぶつかるのは 容量 です。容量が足りなくなる瞬間、システムは遅いディスクを使い始め、そのとき性能が崩れます。

メモリが足りないと — スワップ #

メモリがいっぱいになると、OS はいま使っていないデータをディスクの 1 領域へ移して RAM に空きを作ります。この領域が スワップ (swap) で、移す動作が スワッピング です。Linux のスワップ設定は RHEL 基礎 #6 で実際のコマンドを使って扱いました。

スワップはメモリ不足でプロセスが死ぬのを防ぐ安全装置です。ただし代償が大きいです。先ほどの表を思い出すと、RAM は約 100ns、ディスクはそれより数百から数万倍遅いです。よく使うデータがスワップへ押し出されると、CPU は毎回ディスクを待つことになります。

スワッピングが本格化すると
正常:   CPU → RAM (100ns)                 応答が速い
不足:   CPU → スワップ (ディスク, 数 ms)   応答が数千倍遅くなる
深刻:   読むそばからまた押し出される (スラッシング)   システムがほぼ止まったように見える

データをディスクへ下ろしてすぐまた必要になって上げ、また別のデータを下ろす、ということが繰り返される状態を スラッシング (thrashing) と言います。このとき CPU は計算よりデータを移すことに時間を使い、システムは止まったように遅くなります。「急にサーバーが応答しなくなった」のよくある原因です。

OOM Killer — Linux の最終手段 #

スワップまでいっぱいになり、メモリをこれ以上渡す先がなければ、Linux は OOM Killer (Out Of Memory Killer) を作動させます。メモリを多く使うプロセスを選んで強制終了し、システム全体が止まるのを防ぐ装置です。

運用でデータベースやアプリケーションが「原因なく死んだ」なら OOM Killer を疑います。ログに Out of memory: Killed process のような記録が残ります。解決はメモリを増やすか、プロセスのメモリ使用を減らすか、コンテナならメモリ上限を調整する方向です。

ページキャッシュ — 余ったメモリは遊んでいるのではない #

Linux で free コマンドを見ると、空きメモリが少なく見えて驚く場合が多いです。ほとんどは正常です。Linux は 余った RAM をディスクキャッシュ (ページキャッシュ) として活用 するからです。

一度読んだファイルを RAM にキャッシュしておけば、次に同じファイルをディスクまで行かずに RAM から即座に取れます。このキャッシュはアプリケーションがメモリを必要とすれば即座に返されます。

free -h の読み方
              total   used   free   buff/cache   available
Mem:          16Gi    6Gi    0.5Gi   9.5Gi        9Gi
                                     └─ キャッシュ  └─ 実際に使える量

見るべき値は free ではなく available です。buff/cache は必要なら回収されるので、available が十分ならメモリは足りています。free が 0 に近くても驚く必要はありません。

よく出会う落とし穴 #

「メモリ使用率 90% だけど増設すべきか」 #

数字だけではわかりません。その 90% にページキャッシュが含まれていれば正常です。available が十分か、スワップが実際に起きているかを見れば判断がつきます。

「スワップを入れておけば安全」 #

スワップは死ぬのを防ぐだけで、性能を守ってはくれません。スワップが本格的に使われ始めた時点で、すでに応答は崩れています。応答遅延のアラームとスワップ使用量を一緒に見る必要があります。

「メモリを増やせば速くなる」 #

#1 で押さえた誤解です。足りないときに増やせば崖を避けられますが、十分な状態でさらに増やしても速くはなりません。

「コンテナはホストのメモリを全部使える」 #

上限を掛けなければ、1 つのコンテナがホストのメモリを飲み込んで他のコンテナまで脅かします。運用ではメモリ上限を明示するのが安全です。コンテナのリソース隔離は #7 で扱います。

まとめ #

今回つかんだ絵です。

  • RAM は CPU の作業空間です。速いものの揮発性で限られています。
  • 保存空間は レジスタ → キャッシュ → RAM → SSD → HDD の階層で、1 層下りるたびに速度差が大きく開きます。
  • メモリは 容量・帯域幅・レイテンシ が別々の軸です。運用でもっともよくぶつかるのは容量です。
  • 容量が足りないと スワップ が始まり、ひどくなると スラッシング でシステムが止まったように遅くなります。
  • 渡すメモリがなくなると OOM Killer がプロセスを強制終了します。
  • Linux は余った RAM を ページキャッシュ として使います。free ではなく available を見ます。

次回 — ストレージ #

メモリが足りないときにシステムが落ちる先がディスクでした。そのディスクが次の 2 つの記事の主題です。#4 ストレージ ① デバイス — HDD / SSD / NVMe と IOPS / スループット / レイテンシ では、ディスク 1 枚の種類と性能指標を整理します。HDD、SSD、NVMe が何で、どう違うのか、そして容量とよく混同される IOPS・スループット・レイテンシを切り分けます。

X