Linux 将物理内存分为4k 的页面,而每个进程有自己独立的虚拟内存空间,虚拟内存与物理内存之间的映射关系是通过页表(PageTables)来记录。对于32位的系统,每个页表项需要4个字节来对应一个物理内存4K 页面(64位需要8字节),也就是说,如果用户的虚拟内存空间1GB,那就页表需要1MB的内存。
一、使用4K的页面,页表可能占用大量内存
对于数据库服务器来说,每个服务端进程需要访问的虚拟内存空间比较大(shared_buffer,以及私有内存空间),其对应的页表也比较大。以10GB的shared_buffer为例,如果用户的服务端进程访问了所有buffer,那所需的页表就是10MB,对于500个进程,那就是5GB,这会占用大量的内存。
PS:以上的1GB需要1MB的页表是基于一级页表的计算的结果,如果采用二级页表,那页表需要的空间就只需要8K。相比于一级页表,二级页表性能上有差距,但占用内存空间小很多。不同操作系统在确定页表级数时会在性能与占用空间上进行折中。
可以查看当前操作系统页面大小:
[root@dbhost01 transparent_hugepage]# getconf PAGE_SIZE
4096可以查看 /proc/meminfo 确认PageTables 占用大小
[kingbase@dbhost01 ~]$ cat /proc/meminfo | grep PageTables
PageTables: 34892 kB二、使用大页
4K页面导致页表占用大量空间,而使用大页,通常是2MB,可以减少页表占用空间。此外,大页的内存锁定在物理内存中,不能swapout,这能保证数据库的shared_buffer不被交换出去。
1、关闭 Transparent Huge Pages 透明大页
THP无需预先配置,随着应用需要自动创建、管理、使用大页。进程在需要大内存时,自动会分配大页。如以下KingbaseES 服务端的进程,就使用了THP。
[root@dbhost01 ~]# pmap -d 176489
176489: kingbase: system test [local] idle
Address Kbytes Mode Offset Device Mapping
0000000000400000 8928 r-x-- 0000000000000000 008:00010 kingbase
0000000000eb8000 4 r---- 00000000008b8000 008:00010 kingbase
0000000000eb9000 120 rw--- 00000000008b9000 008:00010 kingbase
0000000000ed7000 332 rw--- 0000000000000000 000:00000 [ anon ]
00000000024dc000 1568 rw--- 0000000000000000 000:00000 [ anon ]
0000000002664000 2304 rw--- 0000000000000000 000:00000 [ anon ]
00007f091f06b000 1544 rw--- 0000000000000000 000:00000 [ anon ]
00007f091f1ed000 44 r-x-- 0000000000000000 0fd:00000 libnss_files-2.28.so
00007f091f1f8000 2048 ----- 000000000000b000 0fd:00000 libnss_files-2.28.so
00007f091f3f8000 4 r---- 000000000000b000 0fd:00000 libnss_files-2.28.so
00007f091f3f9000 4 rw--- 000000000000c000 0fd:00000 libnss_files-2.28.so
00007f091f3fa000 24 rw--- 0000000000000000 000:00000 [ anon ]
00007f091f400000 397312 rw-s- 0000000000000000 000:0000f anon_hugepage (deleted) -- 使用了THP
00007f093784a000 260 rw--- 0000000000000000 000:00000 [ anon ]
......系统使用了多少THP,可以通过查看 /proc/meminfo 确认。
[root@dbhost01 ~]# cat /proc/meminfo | grep AnonHugePages
AnonHugePages: 124928 kB透明大页频繁的创建、删除,容易导致内存碎片。透明大页是默认打开的,分配页的大小并不可控,对于数据库来说并不太推荐。通常,对于数据库来说,需要固定大小的大页,这个是透明大页所提供不了的。因此,通常推荐的是打开大页,并且要关闭透明大页。
可通过如下方式关闭THP。如果想永久关闭THP,必须将以下echo 命令加入到/etc/rc.d/rc.local 文件中。
[root@dbhost01 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
[root@dbhost01 ~]# echo never > /sys/kernel/mm/transparent_hugepage/defrag
[root@dbhost01 ~]# echo never > /sys/kernel/mm/transparent_hugepage/enabled
[root@dbhost01 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
[root@dbhost01 ~]# cat /sys/kernel/mm/transparent_hugepage/defrag
always defer defer+madvise madvise [never]2、使用固定大小的Huge Pages
KingbaseES只有shared buffer、temp_buffers、wal_buffers这些静态分配的内存可以使用大页。而work_mem、maintenance_work_mem、autovacuum_work_mem这些动态内存的分配不会使用大页。如果修改了相关内存参数,需要重新计算操作系统所需的Huge Page数,以防服务端无法启动(分配大页过少)或者部分大页内存没有被使用(分配大页过多)且无法释放而造成浪费。
操作系统配置:
--操作系统内核参数:
vm.hugetlb_shm_group = 0
vm.nr_hugepages = 1024
--/etc/security/limits.conf
* soft memlock 3500000
* hard memlock 3500000关闭透明大页:
修改/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
执行如下命令:
chmod +x /etc/rc.d/rc.local
重启操作系统数据库使用大页:
操作系统配置完成后还需要在数据库层面开启大页,在kingbase.conf中把huge_pages设置成on。注意此设置下如果没有足够的大页面可用,数据库将会启动失败。一般建议默认值try即可。然后重新启动数据库服务生效。重启后,可以通过查看 /proc/meminfo ,确认分配的hugepage 是否被使用。
注意:需要绝对避免操作系统已经分配了HugePage,但数据库启动没有使用大页的场景。这会导致操作系统层大量的内存浪费,引发系统内存不足,甚至引发OOM。
三、什么时候使用大页
Huge Page优势:
- 页表占用内存空间更小,内存访问效率更高;
- Huge Page使用的内存是不可交换(swap)的,没有内存空间换入/换出的开销,同时也避免了因为数据库核心内存被交换产生的性能问题;
- Huge Page使用的内存需要预先分配;且使用固定大小的内存区域,不会被释放;
- 对于写密集型的场景,Huge Page会加大Cache写冲突的发生概率。




