Linuxのヒュージページ設定|THPを無効化してデータベースサーバーの性能劣化を防ぐ方法

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Linuxトラブルシューティング > Linuxのヒュージページ設定|THPを無効化してデータベースサーバーの性能劣化を防ぐ方法
「Redisを再起動するたびに 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無効化のみで警告が消える


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

ヒュージページとは何か|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.

Redisは書き込み時コピー(Copy-on-Write・CoW)を多用します。THP有効時、CoWが発生するたびに2MB単位でページのコピーが走るため、4KB単位のコピーと比べてメモリ使用量が急増し、レイテンシーのスパイクが発生します。BGSAVEやBGREWRITEAOFの実行中にRedisが急に重くなる現象も、多くの場合この仕組みが原因です。

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]

この処理はサーバー負荷が高い時間帯でも容赦なく実行されるため、PostgreSQLのクエリレイテンシーに周期的なジッターが現れます。「CPUやIOに余裕があるのに、なぜかクエリが時々だけ遅い」という現象の多くがこれです。

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前後を目安にする

物理メモリのスロット構成や搭載量の詳細を調べたいときは dmidecode でハードウェア情報を取得 すると、メモリモジュール単位の情報(容量・タイプ・動作クロック)まで確認できます。

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

THP無効化後にBGSAVEの完了時間や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はその代表例で、有効なまま本番運用されているサーバーが今でも多く残っています。設定の見直しは再起動不要で即時反映できるものが多いため、まず現状確認から始めることをお勧めします。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、
メモリ設計・THP・cgroupなど本番チューニングもカバーした2日間ハンズオンセミナーを開催しています。
>>Linuxサーバー構築セミナーの詳細はこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。