手当たり次第に書くんだ

飽きっぽいのは本能

KVM HugePages の基本 – メモリ管理と仮想マシン性能を確認する

KVM で仮想マシンを動かす時、CPU 数、メモリ容量、ディスク I/O には目が向きやすい一方で、メモリをどのページサイズで扱うかは見落とされがちです。その代表的な設定が HugePages です。

HugePages は、Linux がメモリを通常より大きなページ単位で扱えるようにする仕組みです。KVM / QEMU の仮想マシンでは、ゲストメモリを HugePages で backing することで、TLB ミスやページテーブル walk の負荷を下げられる可能性があります。

ただし、HugePages は「有効にすれば必ず速くなる」設定ではありません。メモリを予約する設計、NUMA、VM のメモリサイズ、Transparent HugePages との違い、libvirt の設定、運用上の戻し方まで含めて考える必要があります。この記事では、KVM で HugePages を使う意味と、確認すべきポイントを整理します。

参考
書籍
参考書籍

作って理解する仮想化技術 – ハイパーバイザを実装しながら仕組みを学ぶ

CPU 仮想化、メモリ仮想化、割り込み、仮想デバイスなどを低レイヤーから確認したい場合の参考書籍です。価格や在庫はリンク先で確認してください。

Amazon で見る

このリンクは Amazon アソシエイトリンクです。

HugePages とは何か

Linux は通常、メモリを小さなページ単位で管理します。x86 系では 4KB ページが基本で、プロセスが仮想アドレスを使ってメモリへアクセスすると、CPU はページテーブルを参照して物理アドレスへ変換します。

この変換結果を毎回ページテーブルから引くと遅いため、CPU には TLB、つまり Translation Lookaside Buffer というキャッシュがあります。TLB に変換結果があれば速く処理できますが、TLB に入っていなければページテーブル walk が発生します。

HugePages は、4KB より大きなページを使うことで、1 つの TLB エントリがカバーできるメモリ範囲を広げます。たとえば 2MB の HugePages であれば、4KB ページ 512 個分を 1 つの大きな単位として扱えます。

ページサイズ意味KVM での見方
4KB通常の基本ページ何もしなければ多くのメモリはこの単位で扱われる
2MB一般的な HugePages / THP の代表的サイズVM メモリ backing として使いやすい
1GBより大きな HugePages大容量メモリ VM や NUMA を意識する環境で検討する

なぜ KVM で効く可能性があるのか

仮想化では、メモリアドレス変換が bare metal より複雑になります。ゲスト OS は自分の物理メモリだと思ってメモリを扱いますが、実際にはそれもホスト上の仮想的な領域です。現代の CPU では EPT や NPT のような二段階アドレス変換支援がありますが、それでもメモリ変換の構造は一段ではありません。

HugePages を使うと、ゲストメモリをより大きなページで backing できるため、TLB ミスの回数やページテーブル walk の負荷を減らせる可能性があります。Linux kernel の Transparent Hugepage ドキュメントでも、仮想化と nested page table では TLB ミスの処理や TLB エントリがカバーする範囲が性能に関係することが説明されています。

重要なのは、HugePages が CPU の演算性能を直接上げるわけではないことです。効くのは、メモリ参照が多く、アドレス変換の負荷が無視できないワークロードです。データベース、インメモリ処理、大きな JVM、高速パケット処理、大容量メモリ VM などでは検討する価値があります。

Transparent HugePages と static HugePages の違い

HugePages には、大きく分けて Transparent HugePages と、明示的に予約する HugeTLB / static HugePages があります。両者は同じ「大きなページ」を扱いますが、運用上の性質はかなり違います。

種類特徴KVM での扱い
Transparent HugePageskernel が可能な範囲で自動的に大きなページへまとめる導入は簡単だが、確実に VM メモリを hugepage backing にできるとは限らない
HugeTLB / static HugePages管理者が HugePages を予約し、libvirt / QEMU から明示的に使うVM メモリを計画的に hugepage backing したい場合に向く

THP は手軽です。アプリケーションを変更しなくても、kernel が匿名メモリを大きなページにまとめようとします。一方で、いつ、どの範囲が THP になるかは kernel の判断に依存します。

static HugePages は、あらかじめ HugePages を確保します。予約した HugePages は通常のメモリとして自由には使えず、swap out もされません。その代わり、libvirt の memoryBacking で明示的に VM に使わせる設計ができます。KVM の本番 VM で再現性を重視するなら、こちらを検討する場面が多くなります。

ホストで HugePages の状態を確認する

まず、ホストで HugePages の状態を確認します。現在の HugePages 数やサイズは /proc/meminfo で見られます。

grep -E 'HugePages|Hugepagesize|Hugetlb' /proc/meminfo

典型的には次のような項目が出ます。

HugePages_Total:  0
HugePages_Free:  0
HugePages_Rsvd:  0
HugePages_Surp:  0
Hugepagesize:  2048 kB
Hugetlb:  0 kB
項目意味
HugePages_Total確保されている HugePages の総数
HugePages_Freeまだ使われていない HugePages の数
HugePages_Rsvd予約済みだが、まだ実際には割り当てられていない HugePages の数
HugePages_Surp通常の設定値を超えて一時的に存在する surplus HugePages の数
Hugepagesizeデフォルトの HugePage サイズ
HugetlbHugePages が消費しているメモリ量

対応している HugePage サイズは、/sys/kernel/mm/hugepages でも確認できます。

ls -1 /sys/kernel/mm/hugepages
cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

HugePages を一時的に確保する

検証であれば、まず nr_hugepages に値を書いて一時的に HugePages を確保できます。たとえば 2MB HugePages を 4096 個確保すると、約 8GB になります。

echo 4096 | sudo tee /proc/sys/vm/nr_hugepages

ただし、稼働中のホストでは連続した物理メモリが確保できず、指定数まで増えないことがあります。Linux kernel の HugeTLB ドキュメントでも、起動時に hugepages=N で確保する方法がより確実であると説明されています。

起動時に HugePages を確保する

本番寄りの構成では、kernel command line で HugePages を起動時に確保します。ディストリビューションによって GRUB の設定ファイルや更新コマンドは異なりますが、考え方は同じです。

default_hugepagesz=2M hugepagesz=2M hugepages=4096

1GB HugePages を使う場合は、環境が対応していること、メモリ容量に十分な余裕があること、NUMA ノードとの対応を確認したうえで指定します。

default_hugepagesz=1G hugepagesz=1G hugepages=8

HugePages は予約メモリです。VM が使っていない時でも、予約した分は通常のページキャッシュや他プロセスのメモリとして使えなくなります。ここを理解せずに大きく取りすぎると、ホスト全体のメモリ余裕を失います。

libvirt で VM に HugePages を使わせる

libvirt では、domain XML の memoryBackinghugepages を指定します。libvirt の公式ドキュメントでは、この指定によりゲストメモリを通常の native page size ではなく hugepages で割り当てることが説明されています。

<memoryBacking>
  <hugepages/>
</memoryBacking>

HugePage サイズや NUMA node を明示する場合は、page 要素を使います。

<memoryBacking>
  <hugepages>
  <page size='2' unit='M' nodeset='0'/>
  </hugepages>
</memoryBacking>

VM が 8GB のメモリを持つなら、2MB HugePages では 4096 個が必要です。VM のメモリサイズ、HugePage サイズ、NUMA node、同居 VM の数を合わせて計算します。

VM メモリ2MB HugePages の必要数考え方
4GB20484GB / 2MB
8GB40968GB / 2MB
16GB819216GB / 2MB
32GB1638432GB / 2MB

NUMA と HugePages を分けて考えない

複数 NUMA ノードを持つサーバーでは、HugePages をどの NUMA node に確保するかが重要です。VM の vCPU が node 0 に寄っているのに、メモリ backing が node 1 に偏ると、リモートメモリアクセスが増え、HugePages の効果を相殺することがあります。

KVM のメモリ性能を見る時は、HugePages だけを単独で有効化するのではなく、vCPU pinning、NUMA tuning、emulator thread、IOThread、PCI passthrough の配置と合わせて見ます。HugePages はメモリ backing の設定であり、NUMA 設計から切り離せません。

確認コマンド

設定後は、VM が HugePages を使っているかを確認します。まずホスト全体の HugePages 使用状況を見ます。

grep -E 'HugePages|Hugepagesize|Hugetlb' /proc/meminfo

VM 起動前後で HugePages_FreeHugePages_Rsvd がどう変わるかを見ると、予約と割り当ての動きが分かります。NUMA node ごとの状態を見る場合は、次のように確認します。

grep Huge /sys/devices/system/node/node*/meminfo

QEMU プロセスが使っているメモリ map を見る場合は、対象 PID を確認して smaps を見ます。

pgrep -a qemu-system
sudo grep -E 'KernelPageSize|MMUPageSize|AnonHugePages|Hugetlb' /proc/<pid>/smaps | head -n 40

ただし、smaps の読み方は backing の種類や kernel のバージョンで差が出ます。1 つの項目だけを見て判断せず、libvirt XML、/proc/meminfo、NUMA node ごとの HugePages、VM 起動前後の差分を合わせて確認します。

使うべき場面と使わなくてよい場面

HugePages は、メモリ参照が多い VM や、性能の再現性が重要な VM では有力な選択肢です。一方で、メモリ容量が小さい VM、負荷が軽い VM、頻繁にメモリサイズを変える VM では、得られる効果より運用上の硬さが目立つことがあります。

判断向いている条件注意点
使う価値が高い大容量メモリ VM、DB、低 latency、性能再現性が必要な VM事前予約、NUMA、監視、戻し手順が必要
まず THP でよい小規模 VM、検証環境、効果を大まかに見たい場合再現性や明示性は static HugePages より弱い
無理に使わないメモリが少ないホスト、VM の増減が激しい環境、効果測定しない環境予約メモリがホスト全体の余裕を奪う

HugePages の副作用

HugePages の副作用は、設定そのものが危険というより、メモリを固定的に予約する点にあります。予約した HugePages は通常用途には使いにくく、メモリ pressure が高い時の逃げ道にもなりません。

  • 予約した HugePages は通常のページキャッシュとして使えない
  • VM が起動していなくても予約分のメモリ余裕が減る
  • HugePages が不足すると VM 起動に失敗することがある
  • NUMA node を誤るとリモートメモリアクセスが増える
  • ライブマイグレーションやメモリ ballooning の設計と相性を確認する必要がある

つまり、HugePages は単なる高速化設定ではなく、ホストメモリをどの粒度で、どの VM に、どの NUMA node から割り当てるかを決める設計項目です。

まとめ

KVM における HugePages は、VM のメモリを大きなページで backing し、TLB ミスやページテーブル walk の負荷を下げるための設定です。特に大容量メモリ VM やメモリ参照が多いワークロードでは、性能と latency の安定に効く可能性があります。

一方で、HugePages は万能ではありません。static HugePages はメモリを予約するため、ホスト全体のメモリ設計、NUMA、VM 配置、監視、戻し手順まで含めて考える必要があります。

KVM で HugePages を使うなら、まず /proc/meminfo/sys/kernel/mm/hugepages で状態を確認し、libvirt の memoryBacking で VM に明示的に使わせます。そのうえで、VM 起動前後の HugePages 消費、NUMA node、実際のワークロード性能を見て判断するのが安全です。

参考情報

参考:

関連する記事

あわせて読みたい:

KVM HugePages の基本 – メモリ管理と仮想マシン性能を確認する

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

トップへ戻る