资讯动态

Linux HugePages 配置实战:400G SGA 优化与避坑指南

发布时间:2026/9/30 2:58:36 来源:尧图企业网站定制
简介面向Linux运维与Oracle DBA这份PDF完整梳理HugePages快速配置流程解决大内存数据库因页表开销与内存交换导致的性能瓶颈。内容从memlock无限制设置到vm.nr_hugepages参数计算详细展示hugepages_settings.sh脚本用法与推荐值计算逻辑并包含limits.conf、sysctl.conf关键配置示例同时针对ASM/ASMM、SGA调整等场景给出避坑要点适合需要为Oracle等应用优化内存管理的初中级技术人员。资源包共1个PDF文件53KB体积精炼便于随时查阅。已有1702人学习下载可配合实际操作边看边做。通过文中的配置步骤、命令示例与注意事项读者能独立完成HugePages部署并掌握用ipcs -m查看共享内存段、重启后验证效果等排错思路为后续调优打下基础。1. Linux HugePages 快速配置先算清 400G SGA 的页表账再动手512G 内存的 RHEL 6.8 上跑 Oracle 11.2.0.4SGA 给到 400G——这种配置不开 HugePages页表项数量是亿级的光页表开销就能吃掉几个 GB 内存CPU 大量耗在 TLB miss 上性能掉得肉眼可见。HugePages 的解法很直接把默认 4K 页放大到 2MB页表项数量缩到原来的 1/512且页面锁定不可换出。这篇笔记按 Linux 系统下 HugePages 的实际配置顺序拆完整流程memlock 无限制、用 MOS 401749.1 脚本算 vm.nr_hugepages 建议值、写进 sysctl.conf 生效再用 /proc/meminfo 和 alert 日志双重确认。适合管 Oracle 或大内存 Linux 服务器的 DBA 和运维照着操作即可中间带参数说明和踩坑记录。2. HugePages 工作原理与前置检查页表开销、memlock、AMM 三件事先落地2.1 从 4K 页到 2MB 页页表开销是怎么吃掉 CPU 的Linux 默认内存页是 4KOracle SGA 这类大内存段会被拆成海量小页。以这次环境为例SGA 400G按 4K 页算需要约 1.05 亿个页。x86-64 架构下页表是分级的每页都要对应一个页表项多级目录层层嵌套这些页表项本身要占物理内存400G 地址空间对应下来的页表总开销在 GB 级别。这还没算 CPU 查页表时消耗的时钟周期。CPU 访问内存依赖 TLB 缓存最近用过的页表项TLB 容量是固定的通常只能覆盖几十 MB 到几百 MB 的地址范围。当工作集远大于 TLB 覆盖范围时每次访问都可能触发 TLB missCPU 被迫走多级页表查一次真实地址。数据库场景里 SGA 本身就是高频访问对象这个开销在 OLTP 随机访问负载下会被放大损耗直接反映在响应时间上。HugePages 把页大小提到 2MB同一个 SGA 只需要约 20.48 万个页页表项数量缩到 1/512。下面这个表是本次配置环境的实际对比对比项4K 默认页2MB HugePages400G SGA 页数约 1.05 亿约 20.48 万页表占用内存GB 级几十 MB 级TLB 可覆盖范围几十 MB 量级数 GB 量级这里要区分一个常见误解HugePages 和 Transparent HugePagesTHP不是一回事。我们配置的是显式 HugePagesOracle 在创建共享内存段时明确申请大页而 THP 是内核后台自动合并页的机制。生产环境配 Oracle 大页时THP 反而建议关掉因为它会静默改变内存布局和数据库的预期不一致。很多人看到 /proc/meminfo 里的 AnonHugePages 字段就以为大页生效了实际上那是匿名页的 THP 统计跟本文要配的东西无关这也是后面验证环节容易误判的源头之一。2.2 memlock 与内存锁定SGA 被换出到磁盘的代价HugePages 的页面是锁定在物理内存里、不可换出的这是它稳定的来源。但进程要锁定内存必须先过 memlock 这一关。Linux 的 RLIMIT_MEMLOCK 默认值非常小常见只有 64KBOracle 进程要锁 400G 的 SGA限制必须放开。在 /etc/security/limits.conf 给 oracle 用户配 unlimited 是整个流程的第一步顺序不能反先放开 memlock再算页数再启动实例。memlock 不够时的表现很隐蔽实例能正常启动但 alert 日志里 Large Pages Information 显示 0%整个 SGA 悄悄退回普通 4K 页。数据库自己不报错因为退回普通页是合法的降级路径。这就是「配置了 HugePages 但没生效」这类问题特别迷惑人的原因——表面一切正常实际没吃到任何收益。SGA 被换出到磁盘的代价是灾难性的。buffer cache 命中率崩掉一次逻辑读变成物理读再变成磁盘 IO延迟从微秒级跳到毫秒级整个系统像被卡住。内存锁定正是为了防止这种情况而大页天然具备锁定属性分配出来就固定在物理内存里这也是为什么 HugePages 对数据库的稳定性收益甚至大于性能收益。有个细节容易忽略limits.conf 只对新建会话生效。vi 改完文件当前已登录的 shell 不会自动继承新限制。实际操作中我一般重新 su 或重新 ssh 登录一次然后用 ulimit -l 确认输出 unlimited 再做下一步。这个检查只需要一条命令能省掉后面一大截排查时间。2.3 配置前检查清单内核版本、AMM 状态、共享内存段动配置文件之前把环境确认齐。检查项有四个内核版本uname -r 确认在 2.6 以上脚本根据内核版本输出不同的参数名。大页大小grep Hugepagesize /proc/meminfo 确认是 2048 kB如果被改过页大小后面的计算逻辑要跟着变。AMM 状态查 memory_target 参数大于 0 说明 11g 的 Automatic Memory Management 开着必须先处理。共享内存段ipcs -m 确认数据库实例在跑SGA 对应的大段存在脚本全靠它算页数。这些检查项没有严格先后我习惯合成一条命令uname -r grep Hugepagesize /proc/meminfo ipcs -m | head -20逻辑说明一次输出内核版本、大页大小、共享内存段三样信息确认环境没有明显异常再往下走。head -20 只是限制输出行数实际段多的时候要看全量别漏掉关键段。参数说明uname -r 输出内核版本决定后面脚本走 vm.nr_hugepages 还是 vm.hugetlb_pool 分支grep Hugepagesize 取出大页字节数脚本里所有换算都以它为基础ipcs -m 列出共享内存段各段字节数累加就是建议页数的来源。数据库没启动时这条命令输出会明显偏少看到这种情况就先别往下配。AMM 的检查要进数据库执行show parameter memory_target; show parameter sga_max_size;逻辑说明memory_target 大于 0 说明 AMM 开着。HugePages 和 AMM 冲突这个坑后面单独讲这里先记住只要 AMM 在后面所有配置都没有意义先关掉再说。sga_max_size 是后续计算页数的参照当前 SGA 多大、准备调多大心里要有数。提示前置检查的意义在于把「配置了但没生效」的隐性失败提前暴露。四项检查里任何一项异常都先处理完再进下一章。3. memlock 与 vm.nr_hugepages 配置limits.conf、sysctl.conf 与 MOS 脚本实战3.1 设置 memlock 无限制limits.conf 的正确写法编辑 /etc/security/limits.conf在文件末尾追加两行vi /etc/security/limits.conf # 追加以下两行 oracle soft memlock unlimited oracle hard memlock unlimited逻辑说明soft 和 hard 分别对应软限制和硬限制。软限制是内核强制执行的阈值进程可以在不超过硬限制的前提下自行调整硬限制只有 root 能提高。Oracle 官方安装文档要求两者都设成 unlimited防止数据库运行中因锁定内存不足自动降级到普通页。用户名要跟实际跑 Oracle 实例的操作系统用户一致如果环境里 grid 用户还在跑监听和 ASM 实例同样要加一行。参数说明memlock 单位是 KBunlimited 表示不限制。这里不建议写具体数字比如 41943044G 的 KB 数因为 SGA 调到几百 G 之后这个数字很容易算错而且以后每次调 SGA 都得跟着改。用 unlimited 最省事也最符合 Oracle 对生产环境的建议。改完配置必须重新登录会话然后验证su - oracle ulimit -l逻辑说明su - oracle 会加载目标用户的完整登录环境ulimit -l 输出当前会话的 max locked memory。输出 unlimited 说明 limits.conf 生效如果还是小数字说明会话没重新加载配置或者 PAM 的 limits 模块没启用。参数说明ulimit -l 不带参数显示软限制配合 -H 可以看硬限制验证时两个都看软硬都是 unlimited 才算到位。另外部分发行版需要确认 /etc/pam.d/login 里有 session required pam_limits.so 这一行sshd 登录场景则看 /etc/pam.d/sshd没有就补上否则 limits.conf 根本不会被读取。3.2 用 hugepages_settings.sh 计算建议值脚本逻辑与三种输出MOS 401749.1 提供的 hugepages_settings.sh 是计算 vm.nr_hugepages 建议值最稳的工具。脚本逻辑分四步取内核版本从 /proc/meminfo 读 Hugepagesize遍历 ipcs -m 列出的所有共享内存段按段累加所需页数按内核版本输出对应参数名。脚本头部先做两件基础事KERNuname -r | awk -F. { printf(%d.%d\n,$1,$2); } HPG_SZgrep Hugepagesize /proc/meminfo | awk {print $2}逻辑说明第一行把内核版本提取成主版本.次版本格式比如 2.6、3.10脚本的 case 分支靠它选择输出参数名。第二行从 /proc/meminfo 取出大页大小单位是 KB注意脚本后面换算时又乘了 1024把它变成字节数参与除法。核心计算循环for SEG_BYTES in ipcs -m | cut -c44-300 | awk {print $1} | grep [0-9][0-9]* do MIN_PGecho $SEG_BYTES/($HPG_SZ*1024) | bc -q if [ $MIN_PG -gt 0 ]; then NUM_PGecho $NUM_PG$MIN_PG1 | bc -q fi done逻辑说明循环遍历每个共享内存段的字节数除以大页字节数得到该段至少需要的大页数。注意除完还加了个 1因为段字节数几乎不可能被 2MB 整除多一页做余量避免段边界溢出。所有段累加的结果就是 vm.nr_hugepages 的建议值。参数说明cut -c44-300 取 ipcs -m 输出里从第 44 列开始的字段前 43 列是 key、shmid 等信息字节数从第 44 列开始。如果你的系统 ipcs 输出列位置不同locale 或 util-linux 版本差异脚本可能取不到数字这时可以手动把 ipcs -m 里的字节数按同样公式算。grep [0-9][0-9]* 是过滤掉标题行和空字段确保参与运算的都是纯数字。运行脚本前确认数据库实例是启动状态。脚本开头有交互确认回车继续chmod x hugepages_settings.sh ./hugepages_settings.sh逻辑说明脚本会先打印一段说明回车后开始计算最后一行输出 Recommended setting。同一个环境下SGA 大小不同输出完全不同。我这次实测的三个结果SGA_MAX_SIZE12G 时建议 6148 页SGA_MAX_SIZE400G 时建议 204805 页实例没启动时直接报 ERROR。脚本对实例没启动的处理很明确输出如下************* ERROR ************* Sorry! There are not enough total of shared memory segments allocated for HugePages configuration.这个报错说明脚本找不到可计算的共享内存段不是脚本坏了是环境没就绪。把数据库拉起来再跑一次即可。3.3 写入 sysctl.conf 并生效sysctl -p 的边界拿到建议值后追加到 /etc/sysctl.conf然后加载echo vm.nr_hugepages 204805 /etc/sysctl.conf sysctl -p sysctl vm.nr_hugepages逻辑说明sysctl -p 按配置文件重新加载内核参数vm.nr_hugepages 被设置为 204805。最后一条命令确认运行中的生效值输出应和写入值一致。sysctl -p 只改运行中的内核参数重启后由 /etc/sysctl.conf 自动恢复所以写进配置文件这一步不能省。参数说明vm.nr_hugepages 单位是「页」不是 MB。2MB 大页下204805 页约等于 400GB比 SGA 略大一点是正常的脚本按段向上取整并且预留了余量。开机后 HugePages_Total 可能略小于配置值这是内存碎片导致实际分配不足只要数据库能起来且 alert 日志显示 100%不影响使用。如果差距过大把 vm.nr_hugepages 拆成分批设置先小后大让内核逐段分配最后在配置文件里保留最终值。注意sysctl -w vm.nr_hugepages204805 这种临时写法只对当前运行期有效重启后丢失。一定写进 /etc/sysctl.conf否则下次开机又是一台没开大页的机器。4. 确认 HugePages 生效/proc/meminfo 五字段与 alert 日志双重验证4.1 grep Huge /proc/meminfo五个字段各代表什么意思配置和数据库启动完成后第一层验证看内核统计grep Huge /proc/meminfo输出示例AnonHugePages: 0 kB HugePages_Total: 204805 HugePages_Free: 168475 HugePages_Rsvd: 168471 HugePages_Surp: 0 Hugepagesize: 2048 kB逻辑说明这组字段完整描述了大页的分配和使用状态。判断配置是否成功核心看 HugePages_Total 是否有效、HugePages_Rsvd 是否不为 0。数据库刚启动时 Free 和 Rsvd 接近是正常的随着实例运行触达内存Rsvd 会逐渐转成实际使用。各字段含义整理如下字段含义本次输出HugePages_Total系统实际分配的大页总数204805HugePages_Free尚未使用的空闲大页数168475HugePages_Rsvd已预留但未实际映射的大页数168471HugePages_Surp超出配置额外分配的页数正常为 00Hugepagesize大页大小2048 kB参数说明Free 和 Rsvd 不需要追求某个特定值跟着负载波动是正常的。真正要警惕的是 HugePages_Total 为 0——大页根本没分配出来问题往前找可能是 sysctl.conf 没写、sysctl -p 没执行或者内存碎片严重。另一个极端是 Total 远大于配置值说明有别的进程或脚本额外申请了大页生产环境要查清楚来源。4.2 Oracle alert 日志的 Large Pages Information 段内核层面确认后还要看数据库自己认不认这笔账。实例启动后alert 日志里有一段 Large Pages Information这是 Oracle 自己的判断比 /proc/meminfo 更直接Starting ORACLE instance (normal) ************************ Large Pages Information ******************* Per process system memlock (soft) limit UNLIMITED Total Shared Global Region in Large Pages 400 GB (100%) Large Pages used by this instance: 204801 (400 GB) Large Pages unused system wide 4 (8192 KB) Large Pages configured system wide 204805 (400 GB) Large Page size 2048 KB ********************************************************************逻辑说明重点看两行。Total Shared Global Region in Large Pages 后面是 100%说明整个 SGA 都落在大页上配置成功如果显示 0% 或小于 100%说明部分或全部 SGA 退回普通 4K 页没吃到收益。Per process system memlock (soft) limit UNLIMITED 这行反向验证了 limits.conf 确实被实例读到了。参数说明Large Pages used by this instance: 204801 (400 GB) 表示实例实际占用 204801 个大页。它比配置的 204805 少 4 页这 4 页是系统预留的余量正常现象。如果这里显示的页数明显小于 SGA 应有的页数或者 100% 变成 0%优先查 memlock其次查 AMM 是否残留。alert 日志的位置有固定规律11.2 以后在 $ORACLE_BASE/diag/rdbms/ / /trace/alert_ .log。启动实例后直接 tail 这个文件找 Large Pages Information 段即可ls -t $ORACLE_BASE/diag/rdbms/*/*/trace/alert_*.log | head -1逻辑说明按修改时间倒序找到最新的 alert 日志用 tail 看启动段。更省事的做法是启动实例时同时开一个窗口 tail -f 这个文件启动过程的关键输出都在里面包括大页信息和任何报错。4.3 验证失败时的两条排查路径验证时最容易遇到两种情况各自排查路径不一样。情况一数据库能起来但 alert 日志显示 0%。先回 /proc/meminfo 看 HugePages_Free 是否等于 HugePages_Total。如果相等说明一个大页都没被数据库用掉原因大概率是 memlock 没生效Oracle 进程没有锁定大页的权限。重新登录 oracle 用户执行 ulimit -l 确认 unlimited然后重启实例再看 alert 日志。情况二sysctl -p 执行后HugePages_Total 远小于配置值。这说明系统没有足够连续物理内存分配大页常见于长期运行、内存碎片严重的机器。处理办法是把 vm.nr_hugepages 分成多个批次设置先设小值让内核分配一部分再逐步加大最后在配置文件保留最终值。操作需要 root 权限且建议在维护窗口做。提示这两条路径覆盖了 90% 的验证失败场景。记住一个原则——alert 日志显示 100% 才算配置成功/proc/meminfo 只是辅助证据两者都看别只信其中一个。5. HugePages 配置避坑AMM 冲突、SGA 变更、PGA 漏算五个典型翻车5.1 AMM 与 HugePages 冲突实例起来了但大页全浪费现象数据库 memory_target 大于 0 时配置 HugePages重启实例后 alert 日志显示 0%或实例直接告警无法分配共享内存。原因11g 的 Automatic Memory Management 依赖 /dev/shm 动态调整 SGA 和 PGA内存段是动态映射的而 HugePages 要求共享内存段静态锁定在 2MB 大页上两者机制冲突。MOS 749851.1 明确给出结论AMM 与 HugePages 不兼容。解决把 memory_target 和 memory_max_target 归零改回手动内存管理。数据库里执行 alter system set memory_target0 scopespfile; 和 alter system set memory_max_target0 scopespfile;同时设置 sga_target、sga_max_size、pga_aggregate_target 三个参数重启实例后再跑脚本。ASM 实例同理要配 ASMM 而不是 AMM。5.2 调大 SGA 后 HugePages 全部失效现象配置好的 HugePages 正常运行某次把 SGA_MAX_SIZE 从 300G 调到 400G重启后 alert 日志显示 0%/proc/meminfo 里 HugePages_Free 一直等于 HugePages_Total。原因新 SGA 比原 HugePages 池大放不进去。Oracle 在遇到放不下时选择整体放弃大页而不是部分使用所以表现是「全有或全无」不存在降级到一半的说法。解决按流程清零重算。先把 vm.nr_hugepages 改成 0 或注释掉 sysctl.conf 里那一行重启数据库让新 SGA 起来重新跑 hugepages_settings.sh 拿到新建议值写回 sysctl.confsysctl -p 后再重启数据库。「旧配置清零再重算」这步不能省直接在原值上加页数经常因为内存碎片导致分配不出来。5.3 实例没起来就跑脚本直接报 ERROR现象执行 hugepages_settings.sh 输出 Sorry! There are not enough total of shared memory segments allocated 的 ERROR。原因脚本依赖 ipcs -m 列出的共享内存段计算页数。实例没启动就没有 SGA 共享内存段脚本无米下锅直接退出。解决先启动数据库确认 ipcs -m 能看到百 GB 级的大段再跑脚本。注意脚本只统计运行实例的共享内存段多个实例共存时所有要开大页的实例都得启动否则算出来的建议值偏小。5.4 PGA 漏算内存预算超了现象alert 日志显示 100% 大页一查 free物理内存还是接近耗尽系统出现 swap 活动。原因pga_aggregate_target 不在 SGA 里也不在大页统计范围内。400G SGA 配了 204805 个大页但 PGA 还要额外占几十 G 普通内存。脚本欢迎信息里明确写了 pga_aggregate_target 在 SGA 之外规划总内存预算时很容易漏掉。解决配置前把内存总预算列出来。512G 物理内存SGA 400GPGA 目标 50G加上 OS 和其他进程占用留出至少 10% 余量。PGA 实际使用随负载波动OLTP 通常比 OLAP 小但按 pga_aggregate_target 的值做预算最稳妥。预算超了就压 PGA 或压 SGA重新计算页数后再配。5.5 memlock 配了 unlimitedulimit -l 还是小值现象/etc/security/limits.conf 已经加了 oracle soft/hard memlock unlimited重新 ssh 登录后 ulimit -l 输出还是默认的 64。原因limits.conf 只影响之后新建的会话已登录会话不重新读取。另外部分发行版要确认 PAM 配置里加载了 pam_limits.so否则 limits.conf 根本不生效。解决修改后用 su - oracle 开新会话验证不要用 su oracle后者不加载完整登录环境。ulimit -l 输出 unlimited 再继续。如果还不行检查 /etc/pam.d/login 和 /etc/pam.d/sshd 里有没有 session required pam_limits.so没有就补上。6. 重启后快速复验一条 Linux 常用命令看穿 HugePages 是否还在配置完不是结束重启才是真正的考验。很多环境里配置当时没问题机器一重启 HugePages 就没了原因无非三种sysctl.conf 没写进去、写进去了被其他参数覆盖、内存碎片导致分配失败。我的固定复验习惯是重启后先不启动数据库直接执行grep -E HugePages_Total|HugePages_Free|Hugepagesize /proc/meminfo如果 Total 已经等于配置值说明内核分配成功。如果 Total 是 0先执行 sysctl vm.nr_hugepages 看运行值——运行值是 204805 但 Total 是 0说明系统没分配出足够连续内存这时可以 echo 1 /proc/sys/vm/drop_caches 清一波页缓存再等几秒重试。这个操作要在维护窗口做生产环境别随手执行。数据库启动后的二次确认我习惯写成一条组合命令把内核视图和数据库视图一次打出来grep HugePages_ /proc/meminfo sqlplus -S / as sysdba EOF select name, value from v\$parameter where name in (sga_max_size,memory_target,pga_aggregate_target); EOF逻辑说明第一段确认大页分配和空闲情况第二段直接查数据库当前生效参数确认 memory_target 是 0、sga_max_size 符合预期。两个视图对上了这套配置才算交圈。v$parameter 在 sqlplus 里要转义 $写成 $否则会被 shell 当成变量吞掉。这套复验流程还有个隐藏价值它把「配置了」和「生效了」两件事彻底分开。很多环境的问题恰恰出在「配置了但没生效」比如有人用 sysctl -w 临时改了参数、有人改了 limits.conf 但没重登。复验时只要看一眼 HugePages_Total 和 alert 日志这些半吊子配置立刻现形。从那以后我每次给新库配 HugePages 都强制走一遍配置前先 ipcs -m 确认实例在跑跑完脚本把建议值写进 sysctl.conf 而不是临时生效收尾一定重启一次机器而不是只重启实例再用 grep Huge /proc/meminfo 确认。整套流程半小时以内能避开的坑至少有五个。数据库这种黑匣子配置类操作最怕「感觉配了」——所有生效判断都必须落在具体输出上这是我踩了这么多次坑之后最深的体会。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑