1. PostgreSQL与HUGEPAGE/HUGETLBFS:
当PostgreSQL使用大量连续的内存块时,使用大页面会减少开销,特别是在使用较大的shared_buffers时。要在PostgreSQL中使用此特性,你的内核必须下面两个参数:
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
你还必须调整内核来设置vm.nr_hugepages参数。要估计所需的巨大页面的数量,请启动PostgreSQL,但不启用巨大页面,并使用/proc文件系统来检查postmaster的VmPeak值以及系统的大页面值,如下所示:
# head -1 /data/pgdata/11/postmaster.pid
2078
# grep ^VmPeak /proc/2078/status
VmPeak: 1364552 kB
# grep ^Hugepagesize /proc/meminfo
Hugepagesize: 2048 kB
1364552/2048大约是666,因此在这个示例中你至少需要666个大页面,我们可以这样设置:
# sysctl -w vm.nr_hugepages=666
# echo vm.nr_hugepages=666 >> /etc/sysctl.conf
通常,考虑到机器上的其他程序也需要大页面,设置更大的值也是合适的。
有时候内核会无法立即分配想要数量的大页面,所以可能有必要重复该命令或者重启系统(重启之后应立即将大部分机器的内存转换为大页面)。要验证大页面分配情况,请执行:
# grep Huge /proc/meminfo
AnonHugePages: 59392 kB
HugePages_Total: 666
HugePages_Free: 666
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
可能还需要赋予PostgreSQL服务器的操作系统用户更多权限(属组添加root),让他能通过sysctl来设置vm.hugetlb_shm_group以使用大页面,或赋予使用ulimit -l锁定内存的权限(hugetlb_shm_group contains group id that is allowed to create SysV shared memory segment using hugetlb page. By default, Only root can do that.)。
PostgreSQL中大页面的默认行为是尽可能使用它们并且在失败时转回到正常页面。要强制使用大页面,你可以在postgresql.conf中把huge_pages设置成on。需要说明的时,如果没有足够的大页面可用,那么PostgreSQL将会启动失败。
2. CentOS 7.x启用HUGETLBFS:
参考:https://www.ibm.com/developerworks/cn/linux/l-cn-hugetlb/
随着计算需求规模的不断增大,应用程序对内存的需求也越来越大。为了实现虚拟内存管理机制,操作系统对内存实行分页管理。自内存“分页机制”提出之始,内存页面的默认大小便被设置为4096字节(4KB),虽然原则上内存页面大小是可配置的,但绝大多数的操作系统实现中仍然采用默认的4KB页面。4KB大小的页面在“分页机制”提出的时候是合理的,因为当时的内存大小不过几十兆字节,然而当物理内存容量增长到几G甚至几十G的时候,操作系统仍然以4KB大小为页面的基本单位,是否依然合理呢?
在Linux操作系统上运行内存需求量较大的应用程序时,由于其采用的默认页面大小为4KB,因而将会产生较多TLB Miss和缺页中断,从而大大影响应用程序的性能。当操作系统以2MB甚至更大作为分页的单位时,将会大大减少TLB Miss和缺页中断的数量,显著提高应用程序的性能。这也正是Linux内核引入大页面支持的直接原因。好处是很明显的,假设应用程序需要2MB的内存,如果操作系统以4KB作为分页的单位,则需要512个页面,进而在TLB中需要512个表项,同时也需要512个页表项,操作系统需要经历至少512次TLB Miss和512次缺页中断才能将2MB应用程序空间全部映射到物理内存;然而,当操作系统采用2MB作为分页的基本单位时,只需要一次TLB Miss和一次缺页中断,就可以为2MB的应用程序空间建立虚实映射,并在运行过程中无需再经历TLB Miss和缺页中断(假设未发生TLB项替换和Swap)。
为了能以最小的代价实现大页面支持,Linux操作系统采用了基于hugetlbfs特殊文件系统2M字节大页面支持。这种采用特殊文件系统形式支持大页面的方式,使得应用程序可以根据需要灵活地选择虚存页面大小,而不会被强制使用2MB大页面。
使用hugetlbfs之前,首先需要在编译内核 (make menuconfig) 时配置CONFIG_HUGETLB_PAGE和CONFIG_HUGETLBFS选项,这两个选项均可在File systems内核配置菜单中找到。
内核编译完成并成功启动内核之后,将hugetlbfs特殊文件系统挂载到根文件系统的某个目录上去,以使得hugetlbfs可以访问。命令如下:
# mount none /mnt/huge -t hugetlbfs
# hugeadm --list-all-mounts
Mount Point Options
/dev/hugepages rw,relatime
/mnt/hugetlb rw,relatime
此后,只要是在/mnt/huge/目录下创建的文件,将其映射到内存中时都会使用2MB作为分页的基本单位。值得一提的是,hugetlbfs中的文件是不支持读/写系统调用 (如read()或write()等) 的,一般对它的访问都是以内存映射的形式进行的。
对于系统中已存在的大页面的统计信息可以在Proc特殊文件系统(/proc)中查到,如/proc/sys/vm/nr_hugepages给出了当前内核中配置的大页面的数目,也可以通过该文件配置大页面的数目,如:
# cat /proc/filesystems |grep hugetlbfs
nodev hugetlbfs
# cat /proc/sys/vm/nr_hugepages
1536
# echo 2048 > /proc/sys/vm/nr_hugepages
调整系统中的大页面的数目为20。例子中给出的大页面应用是简单的,而且如果仅仅是这样的应用,对应用程序来说也是没有任何用处的。在实际应用中,为了使用大页面,还需要将应用程序与库libhugetlb链接在一起。libhugetlb库对malloc()/free()等常用的内存相关的库函数进行了重载,以使得应用程序的数据可以放置在采用大页面的内存区域中,以提高内存性能。因此你需要安装libhugetlbfs软件包:
# rpm -qa |grep libhugetlbfs
# yum search libhugetlbfs |grep ^libhugetlbfs
libhugetlbfs-devel.i686 : Header files for libhugetlbfs
libhugetlbfs-devel.x86_64 : Header files for libhugetlbfs
libhugetlbfs.x86_64 : A library which provides easy access to huge pages of
libhugetlbfs-utils.x86_64 : Userspace utilities for configuring the hugepage
# yum install -y libhugetlbfs*
以下内容参考:https://blog.csdn.net/g__hk/article/details/44955587
在Linux系统中,有两种方式可以用来使用hugepages。一种是2.6内核就已经引入的Hugetlbfs虚拟文件系统,还有一种方式就是从2.6.38版本开始(RHEL 6)引入的THP(Transparent Hugepages)。
在现实世界中,hugetlbfs主要用于数据库,需要专门的进行配置以及应用程序的代码支持,而THP则可用于更广泛的应用程序,一切都交给操作系统来完成,也不再需要额外的配置,所以对于应用程序是透明的。 我们首先来看hugetlbfs。hugetlbfs是一个虚拟文件系统,它运行在内核层,不与磁盘空间相对应。如果需要使用hugetlbfs,则需要在编译Linux内核的时候在file system这个配置栏中勾选CONFIG_HUGETLB_PAGE和CONFIG_HUGETLBFS选项(如果勾选了CONFIG_HUGETLB_PAGE则CONFIG_HUGETLBFS会自动勾选)。内核编译完成并启动操作系统以后,将hugetlbfs文件系统挂载到特定的目录(不同的发行版目录可能不一样,Red Hat一般mount在/dev/hugepages),则hugetlbfs就可以访问了。完成以后可以通过下面命令来查看hugetlbfs是否已经开启。
cat /proc/filesystems | grep tlb
因为RHEL/OL提供二进制内核的rpm包,所以这些操作在RHEL/OL都不需要做。RHEL/OL上惟一需要做的就是在nr_hugepages中输入需要使用的hugepages的数量,例如:
echo 10240> /proc/sys/vm/nr_hugepages
当然我们都知道/proc文件系统的内容只对当前生效,如果需要重启后依然有效则需要把vm.nr_hugepages = 25000这个条目加入到/etc/sysctl.conf内核配置文件中,然后重启操作系统或者使用sysctl -p刷新内核参数配置才能生效。如果一个程序要使用hugetlbfs,那么用户只能使用mmap标准的SYSV函数shmget/shmat来调用/访问它。如果使用mmap调用,则在mmap函数的第四个参数带入的标志位为MAP_HUGETLB,具体实例请参考Linux内核文档:https://www.kernel.org/doc/Documentation/vm/map_hugetlb.c。
Working with hugetlbfs large page support:
https://www.ibm.com/support/knowledgecenter/en/linuxonibm/com.ibm.linux.z.lgdd/lgdd_t_largepage_wrk.html
hugepage的优势与使用:
http://sysight.com/index.php?qa=17&qa_1=hugepage的优势与使用
7.3.CONFIGURING HUGETLB HUGE PAGES:
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/performance_tuning_guide/sect-red_hat_enterprise_linux-performance_tuning_guide-memory-configuring-huge-pages
让PostgreSQL启动并使用HUGEPAGE:
# grep HugePages_Total /proc/meminfo
HugePages_Total: 512
# grep Hugepagesize /proc/meminfo
Hugepagesize: 2048 kB
# cat <<EOF >> /etc/sysctl.conf
vm.nr_hugepages = 4096
vm.hugetlb_shm_group = 0
EOF
# sysctl -p
# grep HugePages_Total /proc/meminfo
HugePages_Total: 4096
# grep HugePages_Free /proc/meminfo
HugePages_Free: 4096
# yum install -y libhugetlbfs*
# hugeadm --pool-list
Size Minimum Current Maximum Default
2097152 4096 4096 5632 *
1073741824 0 0 0
# hugeadm --pool-pages-min 2MB:512
# hugeadm --pool-pages-max 2MB:2048
# hugeadm --pool-list
Size Minimum Current Maximum Default
2097152 512 512 2048 *
1073741824 0 0 0
# cat /proc/filesystems | grep tlb
nodev hugetlbfs
# mkdir -p /mnt/hugetlbfs
# mount -t hugetlbfs none /mnt/hugetlbfs -o uid=postgres -o gid=postgres
# chown postgres:postgres /mnt/hugetlbfs
# hugeadm --list-all-mounts
Mount Point Options
/dev/hugepages rw,relatime
/mnt/hugetlbfs rw,relatime,uid=5432,gid=5432
# ls -ld /mnt/hugetlbfs/
drwxr-xr-x 2 postgres postgres 0 Mar 8 14:44 /mnt/hugetlbfs/
# hugeadm --set-recommended-shmmax
# hugeadm --explain
Total System Memory: 32156 MB
Mount Point Options
/dev/hugepages rw,relatime
/mnt/hugetlbfs rw,relatime,uid=5432,gid=5432
Huge page pools:
Size Minimum Current Maximum Default
2097152 512 512 2048 *
1073741824 0 0 0
Huge page sizes with configured pools:
2097152
The recommended shmmax for your currently allocated huge pages is 4294967296 bytes.
To make shmmax settings persistent, add the following line to /etc/sysctl.conf:
kernel.shmmax = 4294967296
To make your hugetlb_shm_group settings persistent, add the following line to /etc/sysctl.conf:
vm.hugetlb_shm_group = 0
Note: Permanent swap space should be preferred when dynamic huge page pools are used.
# mkdir /mnt/hugetlbfs/data
# mount -o defaults,noatime,nodiratime,discard,nodelalloc,nobarrier /dev/mapper/data-lv_file /mnt/hugetlbfs/data/
# ln -s /mnt/hugetlbfs/data/pgdata /data/pgdata
# su - postgres
$ cat ./scripts/start-postgresql.sh
source /home/postgres/scripts/setPGEnvironment.sh
export LD_PRELOAD=libhugetlbfs.so
export HUGETLB_MORECORE=yes
/usr/pgsql-11/bin/pg_ctl --pgdata=$PGDATA --log=$PGDATA/postgresql.log start
$ ./scripts/start-postgresql.sh
$ grep HugePages_Total /proc/meminfo
HugePages_Total: 512
$ grep HugePages_Free /proc/meminfo
HugePages_Free: 505