Linux 标准大页和透明大页
Linux 标准大页和透明大页简介
HugePages是Linux内核的一个特性,它允许更大的页面管理内存,以替代4KB的页面大小。
操作系统把逻辑地址映射成物理地址时,需要把映射关系也存储到一块内存中,这部分内容就是页表(PageTables)。计算机内存是通过表映射(页表)的方式进行内存寻址。CPU 拥有内置的内存管理单元,包含这些页面的列表,每个页面通过页表条目引用。当内存越来越大的时候, CPU 需要管理这些内存页的成本也就越高,这样会对操作系统的性能产生影响。
在64位机器上,目前系统默认内存以4KB为一个页,作为内存寻址的最小单元,随着内存和进程数的不断增大,页表的大小将会不断增大。内存是以块即页的方式进行管理的,当前大部分系统默认的页大小为 4096 bytes 即 4K 。 1MB 内存等于 256 页; 1GB 内存等于 256000 页。
1 2 | [lhrxxt@xmmup ~]$ getconf PAGESIZE 4096 |
在Linux操作系统中,即使是同一块共享内存,每个进程中的逻辑地址也是不相同的,因此不同进程中的映射表项也不相同。在64位的机器上,每个4k页需要占用大约8字节的内存,一台48GB内存的机器,如果分配了24GB的共享内存,则每个进程的页表大小为24GB/4K*8=48MB
;如果连接上500个进程,那么页表的大小将是500*48MB=24GB
。这会立刻把机器上的所有内存吃光【可以得到,大约1G的共享内存,若有一个进程连接,则页表大小大约为2MB】。当然,并不是每个新连接一连接上来就会分配48MB,而是当进程需要建立逻辑地址和物理地址之间的映射关系时才会分配,所以,进程占用的页表空间是缓慢增加的,但最终还是会占用很大的页表内存。
页表是必须装在内存的,而且是在CPU内存,太大就会发生大量miss,内存寻址性能就会下降。
要查看是否存在大页表的问题,可以使用如下的命令来检查页表的大小:
1 2 | [root@lhrdb ~]# cat /proc/meminfo | grep PageTables PageTables: 1932200 kB |
如果发现页表的大小不是几十兆,而是达到了1GB以上,就说明数据库存在此问题。基于共享内存的多进程架构的程序都会存在此问题。
Huge Page就是为了解决这个问题,它使用2MB的大页代替传统小页4KB来管理内存,这样页表大小就可以控制的很小,进而全部装在CPU内存,防止出现miss。在 Linux 中,大页分为两种:一是静态大页面(Static Huge Pages,SHP)也称为标准大页,二是透明大页面(Transparent Huge Pages,THP)。从它们的名字就可以看出,SHP是静态的,而THP是动态的。由于THP是在运行期做分配和管理,因此会有一定程度的延迟,对于内存密集型的应用(例如数据库类)十分不利,必须关闭它。
标准大页(Huge Pages)
Huge pages 是从 Linux Kernel 2.6 后被引入的,目的是通过使用大页内存来取代传统的 4kb 内存页面, 以适应越来越大的系统内存,让操作系统可以支持现代硬件架构的大页面容量功能。
Huge pages 有两种格式大小: 2MB 和 1GB , 2MB 页块大小适合用于 GB 大小的内存, 1GB 页块大小适合用于 TB 级别的内存; 2MB 是默认的页大小。
标准大页的页面大小:
1 2 | [root@docker35 ~]# grep Hugepagesize /proc/meminfo Hugepagesize: 2048 kB |
使用Huge pages优点
- 适合大内存或内存密集型应用(例如数据库)的调优。
- 减小页表尺寸(避免页表过大),降低查找缓存(TLB,Translation Lookaside Buffer)的cache-miss,加速VM内存转换。
- 可以使花费在内存管理上的 CPU 时间更少,从而提高性能。
使用Huge pages缺点
当然使用 Huge pages 也会存在某些缺点:
第一, 首先开启该功能需要进行额外设置,不同的数据库配置方法不同。
第二, 大页内存一旦设置,内存就实际分配出去了,也会一直驻留在内存中,不会被交换出去。若数据库没有使用这部分大页,那么相当于这部分大页内存是白白浪费掉的,因为它不会给文件系统缓存使用,也不能给其它不使用大页内存的程序使用。
透明大页 (Transparent Huge Pages)
Transparent Huge Pages 缩写 THP ,这个是 RHEL 6 开始引入的一个功能,在 Linux6 上透明大页是默认启用的。
由于 Huge pages 很难手动管理,而且通常需要对代码进行重大的更改才能有效的使用,因此 RHEL 6 开始引入了 Transparent Huge Pages ( THP ), THP 是一个抽象层,能够自动创建、管理和使用传统大页。
THP 为系统管理员和开发人员减少了很多使用传统大页的复杂性 , 因为 THP 的目标是改进性能 , 因此其它开发人员 ( 来自社区和红帽 ) 已在各种系统、配置、应用程序和负载中对 THP 进行了测试和优化。这样可让 THP 的默认设置改进大多数系统配置性能。但是 , 不建议对数据库工作负载使用 THP (Oracle、MySQL、PostgreSQL、MongoDB均建议关闭THP),因为THP在运行时动态分配内存,而运行时的内存分配会有延迟,对于数据库的管理来说并不友好,会导致数据库性能抖动,所以建议关闭THP。
这两者最大的区别在于 : 标准大页管理是预分配的方式,而透明大页管理则是动态分配的方式。
THP存在的问题
注:Transparent Huge Pages在32位的RHEL 6中是不支持的。
Transparent Huge Pages (THP) is a Linux memory management system that reduces the overhead of Translation Lookaside Buffer (TLB) lookups on machines with large amounts of memory by using larger memory pages.
However, database workloads often perform poorly with THP,because they tend to have sparse rather than contiguous memory access patterns.
You should disable THP on Linux machines to ensure best performance。
如何关闭 THP?(禁用透明大页)
检查当前的transparent_hugepage状态(以下为开启状态):
1 2 3 4 | [lhrxxt@xmmup ~]$ cat /sys/kernel/mm/transparent_hugepage/defrag [always] madvise never [lhrxxt@xmmup ~]$ cat /sys/kernel/mm/transparent_hugepage/enabled [always] madvise never |
使用命令查看时,如果输出结果为 [always] 表示透明大页启用了,[never] 表示透明大页禁用。
透明大页关闭方法有两种,一种是通过命令关闭,一种通过修改grub开机引导文件关闭:
方法一:使用脚本
1)手动临时关闭
1 2 | echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/defrag |
参数说明:
- never 关闭,不使用透明大页内存
- always 尽量使用透明内存,扫描内存,有512个 4k页面可以整合,就整合成一个2M的页面
- madvise 避免改变内存占用,表示只在 MADV_HUGEPAGE 标志的 VMA 中使用 THP
2)开机自动关闭
1 2 3 4 5 6 7 8 9 10 11 12 | cat >> /etc/rc.local <<"EOF" 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 EOF |
授予执行权限:
1 2 3 4 5 | chmod +x /etc/rc.d/rc.local -- /etc/rc.local是软连接 [root@oracle-rac1 ~]# ll /etc/rc.local lrwxrwxrwx 1 root root 13 Mar 1 16:38 /etc/rc.local -> rc.d/rc.local |
另外,我们也可以配置系统服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | -- 创建服务 cat > /etc/systemd/system/disable-thp.service <<"EOF" [Unit] Description=Disable Transparent Huge Pages (THP) DefaultDependencies=no [Service] Type=simple ExecStart=/bin/sh -c "echo 'never' >/sys/kernel/mm/transparent_hugepage/enabled && echo 'never' >/sys/kernel/mm/transparent_hugepage/defrag" [Install] WantedBy=multi-user.target EOF -- 启用服务 systemctl daemon-reload systemctl start disable-thp systemctl enable disable-thp cat /sys/kernel/mm/transparent_hugepage/defrag cat /sys/kernel/mm/transparent_hugepage/enabled |
方法二:修改系统grub
备份配置文件
1 2 | cp /etc/default/grub /etc/default/grub.`date +%F`.bak ------->>>>备份grub配置文件 cp /boot/grub2/grub.cfg /boot/grub2/grub.cfg.`date +%F`.bak ------->>>>备份grub文件 |
编辑/etc/default/grub
文件,在 GRUB_CMDLINE_LINUX 那一行后面追加 transparent_hugepage=never
例如:
1 2 3 4 5 6 7 8 | # cat /etc/sysconfig/grub GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" GRUB_DEFAULT=saved GRUB_DISABLE_SUBMENU=true GRUB_TERMINAL_OUTPUT="console" GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rd.lvm.lv=centos/usr rhgb quiet transparent_hugepage=never" GRUB_DISABLE_RECOVERY="true" |
再使用 grub2-mkconfig 生成grub.cfg配置文件。
1 2 | # grub2-mkconfig -o /boot/grub2/grub.cfg # init 6 -------->>>>重启生效 |
对于UEFI的机器使用如下命令:
1 2 | cp -pv /boot/efi/EFI/redhat/grub.cfg /boot/efi/EFI/redhat/grub.cfg-bkp grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg |
对于 RHEL 7.x or CentOS 7.x,也可以使用grubby命令:
1 | # grubby --update-kernel=ALL --args="transparent_hugepage=never" |
重启后效果:
1 2 3 4 5 6 7 8 | # cat /proc/cmdline BOOT_IMAGE=/vmlinuz-3.10.0-1127.el7.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rd.lvm.lv=rhel/usr rhgb quiet transparent_hugepage=never [root@oracle-rac1 ~]# cat /sys/kernel/mm/transparent_hugepage/defrag always madvise [never] [root@oracle-rac1 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled always madvise [never] |
For Ubuntu systems, install the hugepages
package and run this command as root:
1 | # hugeadm --thp-never |
扩展内容
使用情况监控
可以查看/sys/kernel/mm/transparent_hugepage/khugepaged下信息
pages_to_scan (默认 4096 = 16MB)
一个扫描周期被扫描的内存页数
scan_sleep_millisecs (默认 10000 = 10sec)
多长时间扫描一次
alloc_sleep_millisecs (默认 60000 = 60sec)
多长时间整理一次碎片
参考文档
HugePages on Oracle Linux 64-bit ( 文档 ID361468.1)
HugePages and Oracle Database 11g AutomaticMemory Management (AMM) on Linux ( 文档 ID 749851.1)
HugePages on Linux: What It Is... and WhatIt Is Not... ( 文档 ID 361323.1)
Oracle Linux: Shell Script to CalculateValues Recommended Linux HugePages / HugeTLB Configuration ( 文档 ID401749.1)
https://www.oracle.com/cn/technical-resources/articles/it-infrastructure/dev-hugepages.html
支持Markdown