Linux 透明大页 THP 和标准大页 HP
作者 | JiekeXu
来源 |公众号 JiekeXu DBA之路(ID: JiekeXu_IT)
大家好,我是JiekeXu,很高兴又和大家见面了,今天和大家一起来看看 Linux 透明大页 THP 和标准大页 HP,欢迎点击上方蓝字关注我,标星或置顶,更多干货第一时间到达!
目 录
标准大页(HugePages)
透明大页(Transparent HugePages)
标准大页和透明大页区别
如何关闭透明大页THP(Transparent HugePages)
THP 禁用方的几种方法
关闭透明大页THP
查看是否关闭透明大页
开启标准大页HP
优点:
缺点:
配置注意事项:
查看页面大小
计算 vm.nr_hugepages 的值
memlock 参数设置
查看是否开启标准大页
标准大页开启步骤
HugePages 优缺点及注意事项
参考链接
在 Linux 中大页分为两种: Huge pages (标准大页) 和 Transparent Huge pages(透明大页)。
内存是以块即页的方式进行管理的,当前大部分系统默认的页大小为 4096 bytes 即 4K 。 1MB 内存等于 256 页; 1GB
内存等于 256000 页。CPU 拥有内置的内存管理单元,包含这些页面的列表,每个页面通过页表条目引用。当内存越来越大的时候,CPU 需要管理这些内存页的成本也就越高,这样会对操作系统的性能产生影响。
如下查询所示,此主机既没有关闭透明大页也没有开启标准大页。
grep Huge /proc/meminfo
RHEL 的官方文档对传统大页(Huge Pages)和透明大页(Transparent Huge Pages)这两者的描述(原文和译文)如下:
Huge pages can be difficult to manage manually, and often require significant changes to code in order to be used effectively. As such, Red Hat Enterprise Linux 6 also implemented the use of transparent huge pages(THP). THP is an abstraction layer that automates most aspects of creating, managing, and using huge pages.
--巨大的页面很难手工管理,为了有效地使用,通常需要对代码进行重大修改。因此,Red Hat Enterprise Linux 6 也实现了使用透明大页面(THP)。THP 是一个抽象层,它可以自动化创建、管理和使用大页面的大部分方面。
THP hides much of the complexity in using huge pages from system administrators and developers. As the goal of THP is improving performance, its developers (both from the community and Red Hat) have tested and optimized THP across a wide range of systems, configurations, applications, and workloads. This allows the default settings of THP to improve the performance of most system configurations. However, THP is not recommended for database workloads. --THP 向系统管理员和开发人员隐藏了使用大页面的复杂性。由于 THP 的目标是提高性能,它的开发人员(来自社区和 Red Hat)已经在广泛的系统、配置、应用程序和工作负载上测试和优化了 THP。这允许THP的默认设置来提高大多数系统配置的性能。但是,不建议对数据库工作负载使用 THP。
标准大页(HugePages)是从 Linux Kernel 2.6 后被引入的,Huge Pages 可以称为大内存页或者大页面,有时候也翻译成大页/标准大页/传统大页。目的是用更大的内存页面(memory page size)以适应越来越大的系统内存,让操作系统可以支持现代硬件架构的大页面容量功能。
# grep -i page /proc/meminfo
AnonPages: 2425276 kB
PageTables: 115136 kB
AnonHugePages: 0 kB
HugePages_Total: 4200
HugePages_Free: 103
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
以上各项含义:
AnonPages:匿名页大小。
PageTables:页面表大小。
HugePages_Total:配的页面数目,和Hugepagesize相乘后得到所分配的内存大小。
HugePages_Free:从来没有被使用过的Hugepages数目。即使oracle sga已经分配了这部分内存,但是如果没有实际写入,那么看到的还是Free的。这是很容易误解的地方(池中尚未分配的 HugePages 数量)
HugePages_Rsvd:已经被分配预留但是还没有使用的page数目。在Oracle刚刚启动时,大部分内存应该都是Reserved并且Free的,随着ORACLE SGA的使用,Reserved和Free都会不断的降低。
HugePages_Surp:“surplus”的缩写形式,表示池中大于 /proc/sys/vm/nr_hugepages 中值的
HugePages 数量。剩余 HugePages 的最大数量由 /proc/sys/vm/nr_overcommit_hugepages
控制。此值为0的情况很常见。
Hugepagesize:页面大小
那么,HugePages 和普通内存页有何差异呢?主要就是 PageTables
的差异,使用不同的页面,PageTables 大小是不同的。PageTables
在字面意思上是指“页面表”。简单地说,就是操作系统内核用于维护进程线性虚拟地址和实际物理内存地址对应关系的表格。
每个进程都会有一份 PageTables,当系统中的进程比较多,例如有几千个会话,PageTables 会很大。比如,一个
96G SGA 的数据库,PageTables 的大小大约为 144M,如果我们的系统中只有 100 个会话,那么大约占用 14.4G
的虚拟内存空间,如果有 1000个 会话,那么就会占用 144G 的虚拟内存,甚至比 SGA
还大。这种内存占用带来的系统换页、内存碎片化等等问题,在某些场景下就会变得十分严重。所以如果你的 SGA 比较大,同时会话数比较多,那么使用
HugePages 就一定会有很好的效果。否则 HugePages 带来的性能提升不会太明显。
HugePages 对于使用共享内存的数据库,进程比较多的数据库都十分有益,但相对而言要手工配置比较麻烦,管理起来不方便,当共享内存超过了
HugePages 的大小之后,便无法使用已配置的 HugePages,需要重新配置并且要重启操作系统。那么,透明大页 Transparent
HugePages 就应用而生了。
透明大页(Transparent HugePages)
透明大页(Transparent Huge Pages)缩写为 THP,透明大页(THP)在 RHEL 6
中默认情况下对所有应用程序都是启用的。内核试图尽可能分配巨大的页面,主内核地址空间本身被映射为巨大的页面,减少了内核代码的
TLB(Translation Lookaside Buffer CPU中一小块缓存)压力。
内核将始终尝试使用大页来满足内存分配。
如果没有可用的巨大页面(例如由于物理连续内存不可用),内核将回退到正常的4KB页面。
THP 也是可交换的(不像 hugetlbfs)。这是通过将大页面分成更小的 4KB 页面来实现的,然后这些页面被正常地换出。
透明大页存在的问题:
Oracle Linux team 在测试的过程中发现,如果 linux 开启透明大页 THP,则 I/O 读写性能降低
30%;如果关闭透明大页 THP,I/O 读写性能则恢复正常。另,建议在 Oracle Database 中不要使用 THP。ORACLE
官方不建议在使用 RedHat 6, OEL 6, SLES 11 and UEK2 kernels
时开启透明大页(THP),因为透明大页存在一些问题:
在RAC环境下,透明大页(THP)会导致异常节点重启和性能问题;
在单机环境中,透明大页(THP)也会导致一些异常的性能问题;
标准大页和透明大页区别
两者区别在于大页的分配机制,标准大页管理是预分配方式,而透明大页管理则是动态分配方式。目前透明大页与传统大页混合使用会出现一些问题,导致性能问题和系统重启。
虽然 Transparent HugePages 类似于 HugePages,但它们是由内核中的 khugepage
线程在运行时动态设置的,而标准的 HugePages 是在启动时预分配的。Oracle 官方建议使用标准的 HugePages 来增强性能。
HugePages_Total 对应内核参数 vm.nr_hugepages,也可以在运行中的系统上直接修改
/proc/sys/vm/nr_hugepages,修改的结果会立即影响空闲内存 MemFree 的大小,因为 HugePages
在内核中独立管理,只要一经定义,无论是否被使用,都不再属于 free memory。
如何关闭透明大页THP(Transparent HugePages)
从Red Hat Enterprise Linux 6、Oracle Linux 6、SUSE 11和Unbreakable
Enterprise Kernel 2
(UEK2)内核开始,透明大面在运行时默认启用。 然而,透明的HugePages可能会导致内存分配的延迟,因为内存是动态分配的。因此,Oracle 建议在所有 Oracle 数据库服务器上禁用透明大页,以避免性能问题。
Linux7 默认情况下是开启透明大页功能的。检查系统对应版本。
[root@node1 ~]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.6 (Maipo)
关闭透明大页THP
[root@node1 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
默认情况下,状态为 always,需要调整为 never。
THP 禁用方的几种方法
方法 1:
A.使用 grubby 查看内核版本
[root@node1 ~]# grubby --default-kernel
/boot/vmlinuz-3.10.0-957.el7.x86_64
grubby --args="transparent_hugepage=never" --update-kernel /boot/vmlinuz-3.10.0-957.el7.x86_64
注意:–update-kernel 后需要使用实际的默认内核版本。
这里是/boot/vmlinuz-3.10.0-95
C.执行 grubby --info 命令查看修改后的默认内核配置
grubby --info /boot/vmlinuz-3.10.0-957.el7.x86_64
D.修改当前的内核配置立即关闭透明大页。
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
方法 2:
[root@node1 ~]# vi /etc/default/grub
GRUB_CMDLINE_LINUX="rd.lvm.lv=rhel/swap rd.lvm.lv=rhel/root rhgb quiet numa=off transparent_hugepage=never"
[root@node1 ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
方法 3:
[root@DB ~]#vi /etc/rc.local
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi
[root@DB ~]# sh /etc/rc.local
方法 4:
临时关闭,然后设置开机自启动。
[root@node1 ~]# echo never > /sys/kernel/mm/transparent_hugepage/enabled
[root@node1 ~]# echo never > /sys/kernel/mm/transparent_hugepage/defrag
[root@node1 ~]# vim /etc/rc.d/rc.local
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi
[root@node1 ~]# chmod +x /etc/rc.d/rc.local
查看是否关闭透明大页
[root@node1 ~]# cat /sys/kernel/mm/redhat_transparent_hugepage/enabled
always madvise [never]
[root@node1 ~]# grep -i AnonHugePages /proc/meminfo
AnonHugePages: 0 kB
如 AnonHugePages不为 0 kB,但是一个很小的值,此时可以忽略。
[root@node1 ~]# cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.10.0-957.el7.x86_64 root=/dev/mapper/rootvg-lvroot ro ipv6.disable=1 net.ifnames=0 crashkernel=auto rd.lvm.lv=rootvg/lvroot rd.lvm.lv=rootvg/lvswap rhgb quiet numa=off transparent_hugepage=never
注意:如果是RHEL6透明大页配置文件为/etc/grub.conf 指向/boot/grub/grub.conf
开启标准大页HP
标准大页适用于:
1.Kernel Version 2.6及更高。
2.Oracle AMM(Automatic Memory
Management)内存管理和 HugePages 不兼容,确保在 AMM 关闭的情况下(ASMM ( Automatic Shared Memory
Management )仍然可以继续使用)启动 HugePages。
查看是否开启标准大页
cat /proc/sys/vm/nr_hugepages --如果为 0 则没有配置标准大页。
grep HugePages_Total /proc/meminfo --如果为 0 则没有配置标准大页。
[root@node1 ~]# cat /proc/sys/vm/nr_hugepages
0
[root@node1 ~]# grep HugePages_Total /proc/meminfo
HugePages_Total: 0
[root@rac19c ~]# cat /proc/sys/vm/nr_hugepages
8200
[root@rac19c ~]# grep HugePages_Total /proc/meminfo
HugePages_Total: 8200
标准大页一般在内核参数 /etc/sysctl.conf 文件中设置,参数文件名为 vm.nr_hugepages,除了此参数外,还需要配置 /etc/security/limits.conf 下的 memlock 参数。下面一起看看这两个参数如何配置。
标准大页开启步骤
标准大页是预分配的,需要手动管理去设置,那么 vm.nr_hugepages 大小设置多少算是合理呢?一般也有好几种方法,且看我一一道来。
查看页面大小
首先查看 Hugepagesize,一般 x86 服务器为 2 M, Linuxone 系统为 1M 大小,不同的内核版本 Hugepage 页面大小可能不一样,也有 4M–256M 等其他大小的,如下查看为 2048kB 即 2M。
grep Hugepagesize /proc/meminfo
Hugepagesize: 2048 kB
计算 vm.nr_hugepages 的值
虽然 Oracle 官方推荐使用 Huge Pages,但是具体是否使用还得考虑实际情况。如果系统经常碰到因为 swap
引发的性能问题就可以考虑启用 HugePage 。另外, OS 内存非常大的系统也可以启用 HugePage 。但是具体多大就一定需要使用
HugePage ?这并没有定论。
当数据库启动时会分配共享内存段大小,即数据库启动状态时可以使用官方推荐的 hugepages_settings.sh 脚本计算 nr_hugepages 大小。
但是当你初次安装数据库时第一次配置此参数,则不能使用脚本去计算了,那么我们只能手动计算此值。标准大页只能用于共享内存段等少量类型的内存,一旦将物理内存作为标准大页分配,就不能再将其作为私有内存使用,故不能占用过大的内存,一般情况下以 Oracle 数据库的 SGA 为参考,一个基本公式为:
vm.nr_hugepages =(所有 SGA 大小 M)/Hugepagesize M + N
我这里一般 DB 的 SGA 为内存的三分之一多点,内存为 ASMM 管理。
例 x86 平台 64G 内存 (64G1024/3)/2M+2=10925
例 x86 平台 32G 内存 (32G1024/3)/2M+2=5463
例 x86 平台 16G 内存 (16G*1024/3)/2M+2=2732
禁止 AMM
如果 Oracle 是 11g 以后的版本,那么默认创建的实例会使用 Automatic Memory Management (AMM) 的特性,该特性与 HugePage 不兼容。在设置 HugePage 之前需要先禁用 AMM。设置初始化参数 MEMORY_TARGET 和 MEMORY_MAX_TARGET 为0即可。使用 AMM 的情况下,所有的 SGA 内存都是在 /dev/shm 下分配的,因此在分配SGA 时不会使用 HugePage。这也是 AMM 与 HugePage 不兼容的原因。
SQL> alter system set memory_target=0 scope=both;
SQL> alter system set memory_max_target=0 scope=spfile;
所以,如果我的 RAC 同一节点上有两个数据库实例和一个 ASMM 管理的 ASM
实例,则为这三者之和除以页面大小。如果实例比较多,计算出来的值的基础上加 N 值,N为 2–10 即可。比如有一套 x86 下的 19c RAC
数据库 SGA 为 18GB,ASMM 管理的 ASM 实例大小为 4GB,则 nr_hugepages 需配置 (18+4)*1024/2+N
=11264+N=11266 就行。不过默认情况下 ASM 实例也是使用 AMM 的,而 ASM 实例不需要很大的 SGA,所以对 ASM
实例使用 HugePages 意义不大,故一般情况下只对 DB 的 SGA 计算 HugePages。
修改 sysctl.conf
vim /etc/sysctl.conf文件,增加如下行:
vm.nr_hugepages=11266
然后执行 sysctl -p 命令,使配置生效。然后检查 /proc/meminfo,如果HugePages_Total 小于设置的数量,那么表明没有足够的连续物理内存用于这些标准大页,需要重启服务器。
临时生效的方法:sysctl -w vm.nr_hugepages=11266 --临时改变,重启失效
除了使用 SGA_MAX_SIZE 计算,也可以通过 ipcs -m 所获取的共享内存段大小计算出更准确的 HugePages_Total。
HugePages_Total=sum(ceil(share_segment_size/Hugepagesize))
也可以使用以下命令计算 hugepage 的大小:
ps -ef |grep MGMTDB|grep -v grep
if [ $? = 0 ];then
echo "vm.nr_hugepages = $(ipcs -m|awk '/[0-9]/{min_pg=int($5/(2*1024*1024));if(min_pg > 0){sum+=min_pg+1}}END{print sum}')"
else
echo "vm.nr_hugepages = $(ipcs -m|awk '/[0-9]/{min_pg=int(($5+1*1024*1024*1024)/(2*1024*1024));if(min_pg > 0){sum+=min_pg+1}}END{print sum}')"
fi
注意:HugePages 需要包含 MGMTDB 的 SGA_TARGET,MGMTDB 缺省SGA_TARGET=1G,如果当前环境安装了 MGMTDB,那么我们在没有 MGMTDB 的节点上计算 HugePages 时需要再加上这 1G。计算时加 ASM 内存大小需要禁用 ASM 的 AMM 自动内存管理。HugePages 需大于 SGA 的值,配置错误可能会导致操作系统无法启动。
memlock 参数设置
memlock 参数指定用户可以锁定其地址空间的内存量。在 /etc/security/limits.conf 文件中添加 memlock 的限制,一般情况下该值略微小于实际物理内存的大小(单位为KB)。比如物理内存是 64GB,可以设置为如下:
oracle soft memlock 60397977
oracle hard memlock 60397977
更精确的计算在 MOS 文档 Doc ID 2511230.1 中有说明,启用 HugePages 内存时,memlock 的值应至少为当前 RAM 的 90%,而禁用 HugePages 内存时,其值应至少为 3145728 KB(3 GB)。
memlock 参数指定用户可以锁定其地址空间的内存量。例如。假设我希望我的 SGA 大小为 32GB。然后,每页有 2MB,我们看的是 32768/2 = 16384 页。16384 不适合设置页面需加 N。因此,将分配 16400 个 HugePages。然后,memlock 将为 16400 * 2048 =33587200,单位为 KB。
vi /etc/security/limits.conf
oracle soft memlock 33587200 ----16400*2048=33587200
oracle hard memlock 33587200
故 memlock 的精确值一般为 vm.nr_hugepages*Hugepagesize 。
然后重新以oracle用户连接到数据库服务器,使用 ulimit -l 命令,可以看到:
max lockedmemory (kbytes, -l) 33587200
不过为了省事,我一般将 memlock 配置为 unlimited 也是可以的。
HugePages 优缺点及注意事项
优点:
1、减少页表(PageTables)大小。
2、HugePages 内存只能锁定在物理内存中,不能被交换到交换区。这样避免了交换引起的性能影响。
3、由于页表数量的减少,使得 CPU 中的 TLB(可理解为CPU对页表的CACHE)的命中率大大提高。
4、针对 HugePages 的页表,在各进程之间可以共享,也降低了 PageTables 的大小。实际上这里可以反映出 Linux
在分页处理机制上的缺陷。而其他操作系统,比如 AIX,对于共享内存段这样的内存,进程共享相同的页表,避免了 Linux 的这种问题。
5、提高 Oracle 性能,减少 SGA 的页交换。
缺点:
与 Oracle AMM 有冲突,但 ASMM 不受影响.
配置注意事项:
1、HugePages 容量需大于 SGA 即可,limits.conf 中 memlock unlimited 。
2、如果数据库使用 MANUAL 方式管理 SGA,需要改为 AUTO 方式,即将SGA_TARGET_SIZE 设置为大于0的值。对于
11g,由于 HugePage 只能用于共享内存,不能用于 PGA,所以不能使用 AMM,即不能设置 MEMORY_TARGET
为大于0,只能分别设置 SGA 和 PGA,SGA 同样只能是 AUTO 方式管理。
参考链接:
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/s-memory-transhuge.html
https://mp.weixin.qq.com/s/1CLV53M-1-pomC5Zsnu_dw
https://www.icode9.com/content-2-1124409.html
https://www.cnblogs.com/kerrycode/p/7760026.html
https://www.jianshu.com/p/391f42f8fb0d
Doc ID 401749.1 hugepages_settings.sh
附件:hugepages_settings.sh 脚本内容
#! /bin/bash
#
# hugepages_settings.sh
#
# Linux bash script to compute values for the
# recommended HugePages/HugeTLB configuration
# on Oracle Linux
#
# Note: This script does calculation for all shared memory
# segments available when the script is run, no matter it
# is an Oracle RDBMS shared memory segment or not.
#
# This script is provided by Doc ID 401749.1 from My Oracle Support
# http://support.oracle.com
# Welcome text
echo "
This script is provided by Doc ID 401749.1 from My Oracle Support
(http://support.oracle.com) where it is intended to compute values for
the recommended HugePages/HugeTLB configuration for the current shared
memory segments on Oracle Linux. Before proceeding with the execution please note following:
* For ASM instance, it needs to configure ASMM instead of AMM.
* The 'pga_aggregate_target' is outside the SGA and
you should accommodate this while calculating SGA size.
* In case you changes the DB SGA size,
as the new SGA will not fit in the previous HugePages configuration,
it had better disable the whole HugePages,
start the DB with new SGA size and run the script again.
And make sure that:
* Oracle Database instance(s) are up and running
* Oracle Database 11g Automatic Memory Management (AMM) is not setup
(See Doc ID 749851.1)
* The shared memory segments can be listed by command:
# ipcs -m
Press Enter to proceed..."
read
# Check for the kernel version
KERN=`uname -r | awk -F. '{ printf("%d.%d\n",$1,$2); }'`
# Find out the HugePage size
HPG_SZ=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
if [ -z "$HPG_SZ" ];then
echo "The hugepages may not be supported in the system where the script is being executed."
exit 1
fi
# Initialize the counter
NUM_PG=0
# Cumulative number of pages required to handle the running shared memory segments
for SEG_BYTES in `ipcs -m | cut -c44-300 | awk '{print $1}' | grep "[0-9][0-9]*"`
do
MIN_PG=`echo "$SEG_BYTES/($HPG_SZ*1024)" | bc -q`
if [ $MIN_PG -gt 0 ]; then
NUM_PG=`echo "$NUM_PG+$MIN_PG+1" | bc -q`
fi
done
RES_BYTES=`echo "$NUM_PG * $HPG_SZ * 1024" | bc -q`
# An SGA less than 100MB does not make sense
# Bail out if that is the case
if [ $RES_BYTES -lt 100000000 ]; then
echo "***********"
echo "** ERROR **"
echo "***********"
echo "Sorry! There are not enough total of shared memory segments allocated for
HugePages configuration. HugePages can only be used for shared memory segments
that you can list by command:
# ipcs -m
of a size that can match an Oracle Database SGA. Please make sure that:
* Oracle Database instance is up and running
* Oracle Database 11g Automatic Memory Management (AMM) is not configured"
exit 1
fi
# Finish with results
case $KERN in
'2.2') echo "Kernel version $KERN is not supported. Exiting." ;;
'2.4') HUGETLB_POOL=`echo "$NUM_PG*$HPG_SZ/1024" | bc -q`;
echo "Recommended setting: vm.hugetlb_pool = $HUGETLB_POOL" ;;
'2.6') echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;;
'3.8') echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;;
'3.10') echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;;
'4.1') echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;;
esac
# End
全文完,希望可以帮到正在阅读的你,如果觉得有帮助,可以分享给你身边的朋友,同事,你关心谁就分享给谁,一起学习共同进步~~~
❤️ 欢迎关注我的公众号,来一起玩耍吧!!!
————————————————————————————
公众号:JiekeXu DBA之路
墨天轮:https://www.modb.pro/u/4347
CSDN :https://blog.csdn.net/JiekeXu
腾讯云:https://cloud.tencent.com/developer/user/5645107
————————————————————————————