前言
本文翻译自红帽 RH442(性能调优)课程
大页简介
Linux 通过大页机制支持大内存页。大多数cpu架构支持多个 page 大小,IA-32架构支持4KiB,2MiB,或4MiB,X86-64架构支持4KiB,2MiB,4MiB和1GiB,RHEL6 和RHEL7 使用默认大页是2MiB,处理器的 TLB 条目数量是固定的,但是随着页面大小的增加,处理器的 TLB 空间也会相应变大。更少的 TLB 条目指向更多的内存意味着 TLB 的命中率会更高,每当 CPU 上下文切换时,内核通常必须刷新正在调度的进程的 TLB 条目。
查看 /proc/meminfo 文件可以查看系统大页的大小
[root@server0 ~]# cat /proc/meminfo
...
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
...
通过设置 vm.nr_hugepages 参数的值可以修改大也的数量
[root@server0 ~]# sysctl -w vm.nr_hugepages=20
vm.nr_hugepages = 20
[root@server0 ~]# cat /proc/meminfo
...
HugePages_Total: 20
HugePages_Free: 20
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
...
只有系统在有足够多连续空闲的内存满足请求的情况下,大页才会被分配;如果条件不满足,系统尽可能的多的满足大页的分配。由于大页必须用连续的内存空间分配,在一个运行的主机上进行分配将可能很困难,随着主机运行时间的推移会产生大量的内存碎片。因为这个原因,一个解决这个问题的方法是在系统启动的时候将大页的参数写到/etc/sysctl.conf文件中,如果这样还是很难分配足够的大页,也可以通过 grub 的内核命令行添加 hugepages=N 方式添加大页,同时也可以在内核命令行参数中修改默认的大页大小 hugepagesz=M (默认是2MiB)。
[root@VMwarePC ~]# vim /boot/grub2/grub.cfg
...
linux16 /vmlinuz-3.10.0-1160.el7.x86_64 root=UUID=8fdb3764-78da-40bd-ac12-b43fc752b4f8 ro crashkernel=auto spectre_v2=retpoline rhgb quiet LANG=en_US.UTF-8 default_hugepagesz=1G hugepagesz=1G hugepages=1
...
[root@VMwarePC ~]# cat /proc/meminfo
...
HugePages_Total: 1
HugePages_Free: 1
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 1048576 kB
...
注意
大页只有支持大页的程序才可以使用,大页会占据内存的空间,这部分空间大多数的进程都是不可以访问的
为了使用大页,进程必须使用mmap系统调用或者shmat和shmget系统调用,如果使用mmap系统调用,必须通过 hugetlbfs 文件系统才能使用大页
[root@serverX ~]# mkdir /largepage #名称任意
[root@serverX ~]# mount -t hugetlbfs none /largepage
Transparent huge pages (透明大页)
RHEL6.2 引入了没有明确开发和系统管理员干涉的支持创建和管理大页的内核功能,这个特征被称为透明的大页(THP),THP 默认是开启的,并且被用来映射所有的内核空间地址到单个大页来减少 TLB 的压力。THP 也被用于映射应用程序用来分配动态内存的匿名内存区域。
THP 不同于标准的大页,当 THP 激活的时候,它被内核自动的分配和管理,它也可以被swap,不像标准的大页。
THP 的可调参数位于以下文件中
[root@serverX ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never # never 为不使用,always 与 madvise 都是使用
当THP设置为 always 或 madvise 守护进程 khugepaged 会自动启动,当设置为 never 时 ,守护进程 khugepaged 会自动关闭,/transparent_hugepage/defrag 参数使用相同的值,并且控制内核是否应该积极使用内存压缩来生成更多的大页面。
检查THP的使用情况
[root@VMwarePC ~]# grep AnonHugePages /proc/meminfo
AnonHugePages: 63488 kB
可以在 grub.conf 中追加以下参数在启动时禁用 THP
transparent_hugepage=never
THP 不建议在数据库中启用,如果有需要可以通过 syctl vm.nr_hugepages 预分配。
注意 在 NUMA 系统中,大页被均匀的分配给所有的 nodes 。但是一个数据库进程应该仅从最接近 cpu 的 NUMA 节点中提取内存以获得最佳效率。为了解决这个问题,并确保一个数据库进程在它的 NUMA 节点上有足够的大页数量,可以进行超额分配以便所有 NUMA 节点上有足够的大页,然后再启动数据库。一旦数据库分配了大页,可以通过调节 vm.nr_hugepages 参数解除过量的大页。
/sys 可以提供每个 NUMA 节点大页的使用情况来帮助你决定系统需要保持多少大页:
grep Huge /sys/devices/system/node/*/meminfo
内存与大页相关的参数详细信息可参考以下文档
/usr/share/doc/kernel-doc-*/Documentation/sysctl/vm.txt
/usr/share/doc/kernel-doc-*/Documentation/vm/hugetlbpage.txt
实验1:管理匿名大页
1、安装内存测试软件bigmem
[root@serverX ~]# yum -y install bigmem
2、确保透明大页已启用
[root@serverX ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
3、查看当前匿名大页的使用情况
[root@serverX ~]# cat /proc/meminfo
… …
AnonHugePages: 77824 kB #76MiB
… …
4、使用 bigmem 分配512M内存
[root@serverX ~]# bigmem -T 512 #分配 512M 内存
5、重新开启一个终端查看匿名大页的使用情况
[root@serverX ~]# cat /proc/meminfo
… …
AnonHugePages: 471040 kB
… …
6、回到第一个终端输入 Enter 结束 bigmem 进程。
[root@server0 ~]# bigmem -T 512
Attempting to allocate 64 8MiB pages.
This should result in anonymous hugepages
Allocated 80MiB
Allocated 160MiB
Allocated 240MiB
Allocated 320MiB
Allocated 400MiB
Allocated 480MiB
Press <Enter> to exit
[root@server0 ~]#
实验2:管理标准大页
1、挂载 hugetlbfs 文件系统,确保标准大页可用
[root@serverX ~]# mkdir /hugepages
[root@serverX ~]# mount -t hugetlbfs none /hugepages
2、查看大页使用情况
[root@serverX ~]# grep Huge /proc/meminfo
AnonHugePages: 61440 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
3、通过 sysctl 启用512个大页
[root@server0 ~]# sysctl -w vm.nr_hugepages=512
vm.nr_hugepages = 512
4、再次查看大页的基本信息
[root@serverX ~]# grep Huge /proc/meminfo
AnonHugePages: 69632 kB
HugePages_Total: 512
HugePages_Free: 512
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
5、用 bigmem 分配256M由大页支持的共享内存
[root@serverX ~]# bigmem -H 256
6、重新开启一个终端查看大页的使用情况
[root@serverX ~]# grep Huge /proc/meminfo
AnonHugePages: 69632 kB
HugePages_Total: 512
HugePages_Free: 512
HugePages_Rsvd: 128 #给bigmem预留了256M
HugePages_Surp: 0
Hugepagesize: 2048 kB
7、回到第一个终端输入 Enter 结束 bigmem 进程。
[root@server0 ~]# bigmem -H 256
Attempting to allocate 128 hugepages...
Assuming 2MiB hugepages...
Press <Enter> to exit
[root@server0 ~]#