午前2時、4KBがボトルネックになった時
ある日の午前2時、Proxmox上のRedisとPostgreSQLのクラスタと格闘していた時のことです。RAMの空き容量は十分でCPU負荷も低かったのですが、アプリケーションのレイテンシが異常に高くなっていました。ハイスペックなハードウェアにもかかわらず、システムが「カクつく」ような動作をしていました。perfや/proc/meminfoで調査した結果、主な原因はTLB(Translation Lookaside Buffer)ミスの過多であることに気づきました。
デフォルトでは、Linuxは4KBsのページ単位でメモリを管理します。32GBのRAMを搭載した仮想マシン(VM)の場合、システムは800万以上のページを扱う必要があります。CPUがデータにアクセスするたびに、この膨大なページテーブルを検索しなければなりません。このテーブルがキャッシュ(TLB)の容量を超えると、CPUは「データがどこにあるか」を調べるためだけに、絶えずRAMにアクセスせざるを得なくなります。Huge Pagesは、ページサイズを2MBや1GBに拡大することで、この無駄を解消するために生まれました。
私のホームラボ環境では、現在12個のVMとコンテナが稼働しており、本番環境にデプロイする前のテスト場となっています。データベースのような負荷の高いワークロードでは、Huge Pagesを使用しない場合、メモリ管理のためだけにCPUパフォーマンスの10〜15%を浪費しているというのが実情です。
3つのメモリ管理手法:どれを選ぶべきか?
1. 標準ページ (4KB) – 馴染み深いが負荷が高い
小規模なプロセスには柔軟で適したデフォルト設定です。しかし、数十GBのRAMを積んだVMでは、ページ数が多すぎてCPUが検索時に息切れし、大きな負担となります。
2. 透明なHuge Pages (THP) – 便利だがリスクあり
Linuxが必要に応じて4KBのページを自動的に2MBにまとめます。一見良さそうですが、本番環境では突然の「ラグ」が発生しがちです。khugepagedプロセスがページの再構成を行う際にI/Oブロックを引き起こすため、OracleやRedisのエキスパートは真っ先にこの機能をオフにすることを推奨しています。
3. 静的なHuge Pages – 着実で確実
私が推奨する選択肢です。起動時に一定量のRAMをHuge Pagesとして固定的に割り当てます。このRAMは完全に「専有」され、スワップアウトされることはありません。KVM仮想化において、最も安定した高いパフォーマンスを提供します。
メリットとデメリットの検討
- メリット:
- TLBミスが顕著に減少。CPUはテーブル検索ではなくロジックの処理に集中できるようになります。
- メモリが物理RAMにロック(固定)されます。スワップに追い出されることがないため、極めて低いレイテンシが保証されます。
- ページテーブルが大幅に軽量化されるため、カーネルのオーバーヘッドが減少します。
- デメリット:
- Huge Pagesに割り当てたRAMは「戻ってこない」リソースとなります。VMが使い切らなくても、他のプロセスが借用することはできません。
- 設定を安定して反映させ、メモリの断片化を避けるためにホストの再起動が必要です。
- RAM Ballooning(VMメモリの動的伸縮)機能が無効になります。
なぜProxmoxでStatic Huge Pagesを選ぶのか?
小規模なホスティングであれば、リソースのオーバーコミットができるRAM Ballooningは便利です。しかし、エンタープライズ向けのデータベースでは、安定性が最優先です。私は柔軟性を犠牲にしてでも、ページフォールトによるRedisのラグを排除したいと考えます。128GBのRAMを搭載したサーバーであれば、通常64GB〜80GBをHuge Pagesとして固定的に割り当てます。
詳細な導入手順
以下は、現在最も一般的で導入しやすい2MBのHuge Pagesを設定する手順です。
ステップ 1: ハードウェア情報の確認
まず、以下のコマンドでCPUがHuge Pagesをサポートしているか確認します:
grep -i hugepages /proc/meminfo
ステップ 2: カーネルパラメータの設定
起動時にメモリを割り当てるようGrubを編集します。例として、20GBのRAMをHuge Pages(2MBタイプ)として割り当てる場合、10240ページになります。
nano /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT行にパラメータを追加します:
# 2MB x 10240ページ = 20GBを割り当て
GRUB_CMDLINE_LINUX_DEFAULT="quiet default_hugepagesz=2M hugepagesz=2M hugepages=10240"
Grubを更新してサーバーを再起動します:
update-grub
reboot
ステップ 3: 結果の確認
再起動後、以下のコマンドでRAMが「予約」されているか確認します:
grep Huge /proc/meminfo
HugePages_Freeの値が、先ほど設定した10240に近い数値になっていれば成功です。
ステップ 4: 仮想マシン(VM)への適用
次に、Proxmoxに対して、通常のRAMではなくHuge PagesからVMへメモリを割り当てるように設定します。
CLIを使うと素早く設定できます:
# 100をあなたのVM IDに置き換えてください
qm set 100 -hugepages 2
重要な注意点:設定を有効にするには、VMを一度完全にシャットダウンしてから起動(パワーサイクル)する必要があります。
ステップ 5: 最終確認
VMの稼働中に、ホスト側で再度確認します:
grep HugePages_Free /proc/meminfo
もしFreeの値がVMのメモリ容量分だけ減少していればおめでとうございます。あなたのシステムは今、高速なメモリ上で快適に動作しています。
実地でのちょっとした注意点
64GB以上の非常に大きなVMの場合、1GBのHuge Pages(hugepagesz=1G)の方が効果的です。ただし、これにはより厳格なハードウェアサポートが必要です。
また、Huge Pagesを使用している場合、一部の古いQEMUバージョンではRAMを含むスナップショットでエラーが発生することがあります。インフラの変更後は、バックアップ手順を常に念入りにテストしてください。
システムの最適化は魔法ではなく、カーネルとハードウェアがどのように動作するかを理解することです。この深夜の試行錯誤が、皆さんのシステムをよりスムーズにする助けになれば幸いです!

