WARNING you have Transparent Huge Pages (THP) support enabled というログが出る。」「PostgreSQLのクエリが5秒に1度だけ急に遅くなる、周期的な性能劣化が起きている。」
この2つの現象、根っこは同じです。Linuxの「透過的ヒュージページ(Transparent Huge Pages・THP)」が、データベースサーバーのメモリ管理に干渉してパフォーマンスをこっそり削っています。
この記事では、THPとは何か・なぜ問題になるかを解説したうえで、RHEL 9 / Ubuntu 24.04 LTS環境でのTHP無効化手順と永続化、さらに明示的ヒュージページ(vm.nr_hugepages)を活用してPostgreSQL・Redisの性能を引き出す設定方法まで実機コマンドで解説します。
この記事のポイント
・THP有効時、Redis・DBの周期的遅延・レイテンシスパイクが発生する
・THPはsysfsでneverに設定し、systemdユニットで永続化する
・vm.nr_hugepagesでヒュージページ数を確保し/proc/meminfoで監視する
・PostgreSQLはhuge_pages=onで適用、RedisはTHP無効化のみで警告が消える
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
ヒュージページとは何か|4KBページと2MBページの違い
Linuxカーネルは物理メモリを「ページ」単位で管理しています。x86-64アーキテクチャのデフォルトページサイズは4KBです。この仕組みのもとで大量のメモリを使うアプリケーション(データベース・JVM・Redisなど)が動くと、ページテーブルのエントリ数が膨れ上がり、TLB(Translation Lookaside Buffer)ミスが増えてメモリアクセスが遅くなります。ヒュージページ(HugePage)は、1ページを2MB(または1GB)に拡張することでページテーブルエントリ数を大幅に削減し、TLB効率を上げるカーネルの機能です。メモリ集約型のサーバーサイドアプリケーションで特に効果を発揮します。
| 種類 | サイズ | 管理方法 | 主な用途 |
|---|---|---|---|
| 通常ページ | 4KB | カーネル自動管理 | 汎用 |
| ヒュージページ(明示的) | 2MB / 1GB | 管理者が事前確保 | Oracle DB / PostgreSQL / Redis |
| 透過的ヒュージページ(THP) | 2MB | カーネルが自動管理 | 汎用(DB環境では問題の元凶) |
透過的ヒュージページ(THP)が引き起こす性能問題
THPはLinux 2.6.38以降でデフォルト有効になった機能で、「アプリを修正しなくてもヒュージページの恩恵を受けられる」というコンセプトで導入されました。ところが実際には、データベースやインメモリキャッシュに対してしばしば負の効果をもたらします。1. RedisがTHP警告を出す理由|書き込み時コピーとの相性の悪さ
Redisを起動すると次のような警告が出ることがあります。# Redis起動ログ(/var/log/redis/redis-server.log) WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot.
2. PostgreSQLの周期的クエリ遅延|khugepaged の非同期コンパクション
THP有効時、バックグラウンドデーモンkhugepagedが常時動作し、4KBページを2MBページに再編成しようとします。# khugepaged が動いていることを確認 $ ps aux | grep khugepaged | grep -v grep root 22 0.0 0.0 0 0 ? S 09:01 0:00 [khugepaged]
THPを無効化する手順(RHEL 9・Ubuntu 24.04対応)
1. 現在のTHP状態を確認する
# THPの現在状態を確認([]で囲まれた値が現在の設定) $ cat /sys/kernel/mm/transparent_hugepage/enabled [always] madvise never # defrag設定も確認(khugepaged がメモリを積極的に再編成するかどうか) $ cat /sys/kernel/mm/transparent_hugepage/defrag [always] defer defer+madvise madvise never
alwaysが選択されている場合はすべてのメモリにTHPが適用されます。madviseはmadvise(MADV_HUGEPAGE)を呼び出したプロセスだけに適用、neverは完全無効です。データベースサーバーではneverが推奨設定です。2. その場でTHPを無効化する
# THPを即時無効化 # echo never > /sys/kernel/mm/transparent_hugepage/enabled # defragも無効化(khugepaged によるメモリ再編成を抑制) # echo never > /sys/kernel/mm/transparent_hugepage/defrag # 変更後に確認 $ cat /sys/kernel/mm/transparent_hugepage/enabled always madvise [never]
3. systemdサービスで永続化する(推奨)
RHEL 9やUbuntu 24.04では/etc/rc.localが廃止・無効化されていることが多いため、systemdの一回起動ユニットとして設定するのが確実です。# /etc/systemd/system/disable-thp.service を作成 # cat > /etc/systemd/system/disable-thp.service << 'EOF' [Unit] Description=Disable Transparent Huge Pages (THP) DefaultDependencies=no After=sysinit.target local-fs.target Before=basic.target [Service] Type=oneshot ExecStart=/bin/sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled && echo never > /sys/kernel/mm/transparent_hugepage/defrag" RemainAfterExit=yes [Install] WantedBy=basic.target EOF # 有効化・即時起動(--now で enable と start を一度に実行) # systemctl daemon-reload # systemctl enable --now disable-thp.service # 動作確認 $ systemctl status disable-thp.service * disable-thp.service - Disable Transparent Huge Pages (THP) Loaded: loaded (/etc/systemd/system/disable-thp.service; enabled; vendor preset: disabled) Active: active (exited) since Thu 2026-10-09 09:05:22 JST; 2min ago Process: 1234 ExecStart=/bin/sh -c echo never > ... (code=exited, status=0/SUCCESS) # THP状態を再確認 $ cat /sys/kernel/mm/transparent_hugepage/enabled always madvise [never]
systemctl enable --nowで有効化と起動を同時に行うのがポイントです。enableとstartを別々に実行すると片方を忘れるミスが起きやすいです。4. GRUBオプションでの永続化(補足)
systemdサービス方式を優先しますが、GRUBカーネルパラメータでも設定できます。/etc/default/grubのGRUB_CMDLINE_LINUXにtransparent_hugepage=neverを追記し、GRUBを更新します。# /etc/default/grub の GRUB_CMDLINE_LINUX に追記 GRUB_CMDLINE_LINUX="... transparent_hugepage=never" # RHEL 9系(BIOSブート) # grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL 9系(UEFIブート) # grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg # Ubuntu(UEFI/BIOS共通) # update-grub
明示的ヒュージページ(vm.nr_hugepages)の設定手順
THPを無効化した状態で、Oracle DBやPostgreSQLに対して明示的ヒュージページを割り当てると、TLB効率のさらなる向上が期待できます。THPとは異なり、管理者が確保枚数を明示的にコントロールできる点が大きな違いです。1. 確保するヒュージページ数を計算する
# 物理メモリ量を確認 $ free -h total used free shared buff/cache available Mem: 31Gi 11Gi 16Gi 128Mi 3.8Gi 19Gi # ヒュージページ1枚 = 2MB # PostgreSQLのshared_buffersが8GB → 8192MB ÷ 2MB = 4096ページが最低ライン # OSカーネルやその他プロセス分の余裕として1割増しの4500前後を目安にする
2. vm.nr_hugepagesを設定してsysctlで永続化する
# その場で設定(即時反映) # sysctl -w vm.nr_hugepages=4096 # 確認 $ sysctl vm.nr_hugepages vm.nr_hugepages = 4096 # 永続化(/etc/sysctl.d/ に置くのがRHEL9/Ubuntu24.04の推奨) # echo "vm.nr_hugepages = 4096" > /etc/sysctl.d/99-hugepages.conf # sysctl -p /etc/sysctl.d/99-hugepages.conf
3. /proc/meminfoでヒュージページ使用状況を確認する
$ grep -i huge /proc/meminfo AnonHugePages: 0 kB # THP=never なので0 ShmemHugePages: 0 kB FileHugePages: 0 kB HugePages_Total: 4096 # 確保した明示的ヒュージページ数 HugePages_Free: 3200 # 空き(Total - アプリが使用中) HugePages_Rsvd: 896 # 予約済み(PostgreSQL起動直後は増える) HugePages_Surp: 0 # サープラス(通常は0) Hugepagesize: 2048 kB # 1ページ = 2MB Hugetlb: 8388608 kB # ヒュージページ合計(4096 × 2MB = 8GB)
HugePages_Freeが常時ほぼ0になっている場合はvm.nr_hugepagesの値が不足しています。HugePages_Rsvd(予約済み)も含めた上で余裕が出る数値に設定してください。PostgreSQL・Redisでのヒュージページ設定例
1. PostgreSQL: huge_pages = on でshared_buffersをヒュージページに割り当てる
vm.nr_hugepagesを設定したあと、PostgreSQL側でもヒュージページを使うようにpostgresql.confを変更します。# PostgreSQLが使用しているシェアードメモリ量を把握する $ head -1 /var/run/postgresql/*.pid 1234 $ grep VmRSS /proc/1234/status VmRSS: 524288 kB # 約512MB → 256ページ分が目安 # /etc/postgresql/16/main/postgresql.conf(バージョンは環境に合わせる) # huge_pages = try ← デフォルト(確保できなければ通常ページで起動) huge_pages = on # 確保できない場合はエラーで起動停止(推奨) # PostgreSQLを再起動 # systemctl restart postgresql # ヒュージページが使われているか確認 $ grep -E 'HugePages_(Free|Rsvd)' /proc/meminfo HugePages_Free: 2944 HugePages_Rsvd: 1152 # 増加していればPostgreSQLが予約している
huge_pages = try(デフォルト)は確保できなければ通常ページで動くため、設定ミスに気づきにくいです。明示的にonにしておくことで、ヒュージページが不足した場合に起動エラーとして表面化するため、設定の抜け漏れを防げます。PostgreSQLのshared_buffersは本番サーバーで物理メモリの25~40%程度に設定するケースが多く、それに見合ったヒュージページ確保量の設計が重要です。Linuxサーバーのメモリ設計を含め体系的に学びたい方は Linuxサーバー構築セミナー を参考にしてみてください。
2. Redis: THP無効化で警告を解消する
RedisはPostgreSQLとは異なり、明示的ヒュージページは使いません。THP無効化だけで警告と遅延スパイクを解消できます。# THP=never にした状態でRedisを再起動 # systemctl restart redis # 起動ログでTHP警告が消えているか確認 $ journalctl -u redis --since "1 min ago" | grep -i thp (出力なし → 警告が解消された) # Redis INFO コマンドでメモリ状況も確認 $ redis-cli info memory | grep -E '(used_memory_human|mem_allocator)' used_memory_human:2.51G mem_allocator:jemalloc-5.3.0
redis-cli --latencyのスパイク頻度を計測すると、改善効果を実測で確認できます。うまく設定できない時のトラブルシュート
1. vm.nr_hugepagesが設定値まで増えない
メモリの断片化が進んでいる状態でヒュージページを大量に確保しようとすると、連続した2MB領域を確保できずにvm.nr_hugepagesが設定値より少なくなることがあります。# HugePages_TotalがNr_hugepages設定値より少ない場合 $ grep HugePages /proc/meminfo HugePages_Total: 3800 # 4096を設定したのに3800しか確保できていない # 対処1: カーネルにメモリコンパクションを依頼してから再設定する # echo 1 > /proc/sys/vm/compact_memory # sysctl -w vm.nr_hugepages=4096 # 対処2: ページキャッシュを解放してから確保する(メンテナンス時間帯推奨) # sync; echo 3 > /proc/sys/vm/drop_caches # sysctl -w vm.nr_hugepages=4096 # 対処3: ブート直後に設定されるよう/etc/sysctl.d/に書いておく(最も確実) # メモリが断片化する前のブート直後なら確保しやすい
drop_cachesの実行が一時的なIO増加を招くため、メンテナンス時間帯に行うか、/etc/sysctl.d/99-hugepages.confを使って起動時に自動設定されるよう構成するのが安全です。2. THPを無効化したのに再起動後にalwaysに戻る
# 再起動後にTHP状態を確認 $ cat /sys/kernel/mm/transparent_hugepage/enabled [always] madvise never # never に戻っていない # systemdサービスが有効化されているか確認 $ systemctl is-enabled disable-thp.service disabled # enable できていなかった # 修正: 有効化してから再起動 # systemctl enable disable-thp.service # 有効化が完了したか確認 $ systemctl is-enabled disable-thp.service enabled
systemctl start(即時起動)とsystemctl enable(次回ブートから自動起動)は別物です。両方を忘れずに設定するために、最初からenable --nowオプションを使うことを習慣にしてください。本記事のまとめ
| やりたいこと | コマンド・設定 |
|---|---|
| THP状態を確認する | cat /sys/kernel/mm/transparent_hugepage/enabled |
| THPをその場で無効化する | echo never > /sys/kernel/mm/transparent_hugepage/enabled |
| THP無効化をsystemdで永続化する | systemctl enable --now disable-thp.service |
| 明示的ヒュージページを確保する | sysctl -w vm.nr_hugepages=4096 |
| ヒュージページ使用状況を確認する | grep -i huge /proc/meminfo |
| PostgreSQLでヒュージページを使う | huge_pages = on(postgresql.conf) |
| メモリ断片化でTotalが増えない時 | echo 1 > /proc/sys/vm/compact_memory後に再設定 |
データベースサーバーに限らず、Linuxサーバーのメモリ設計は「何も設定しなければデフォルトのまま動く」ことが多いため、問題が起きるまで気づかないケースが多いです。THPはその代表例で、有効なまま本番運用されているサーバーが今でも多く残っています。設定の見直しは再起動不要で即時反映できるものが多いため、まず現状確認から始めることをお勧めします。
メモリ設計・THP・cgroupなど本番チューニングもカバーした2日間ハンズオンセミナーを開催しています。
>>Linuxサーバー構築セミナーの詳細はこちら
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:chrootコマンドでLinuxシステムを救済・修復する方法|起動不能・パッケージ破損・GRUB修復の実践手順
- この記事の属するカテゴリ:Linuxトラブルシューティングへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます