openGauss 支持使用标准大页来分配共享内存,以提高数据库性能。

  • 减少页表内存占用
  • 减少页表维护开销
  • 提高快表(TLB)命中率
  • 减少缺页中断次数

环境

  • aarch64
  • openEuler 22.03 LTS-SP4

查询大页配置与状态

标准大页与普通内存是独立开的,预留的大页会占用内存容量。 比如扩大大页池容量(增加大页预留数量)之后,可通过 free 命令观察到可用内存的减少。

# 查询系统支持的大页大小
ls /sys/kernel/mm/hugepages

# 查询当前大页大小、预留数与分配数
cat /proc/meminfo | grep Huge

# 查询内存使用情况
free -h

# 查询 NUMA 各节点大页预留数与分配数
cat /sys/devices/system/node/node*/meminfo | grep Huge

# 查询 NUMA 各节点内存使用情况
numactl -H

配置大页池容量

大页池与普通内存池的机制类似:

  • 大页池最初预留的空闲大页数量与容量相等。
  • 所有的空闲大页用自由表维护
  • 从自由表中取出空闲大页分配给上层应用
  • 上层应用释放大页
    • 如果大页总数超过大页池容量,被释放的大页会恢复为普通内存
    • 如果大页总数不超过大页池容量,被释放的大页会被塞回自由表
# 查询大页池容量
cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

# 配置大页池容量
echo <huge-page-cnt> > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

# 查询单个 NUMA 节点大页池容量
cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages

# 为单个 NUMA 节点配置大页池容量
echo <huge-page-cnt> > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages

修改大页大小

需要修改 GRUB 配置并重启。

修改 /etc/default/grub 文件,找到 GRUB_CMDLINE_LINUX,在里面添加参数以指定大页大小,比如:

GRUB_CMDLINE_LINUX="... default_hugepagesz=2M hugepagesz=2M"

我们还可以在这里直接指定大页池容量,就不需要每次重启后手动配置了,比如:

GRUB_CMDLINE_LINUX="... default_hugepagesz=2M hugepagesz=2M hugepages=512"

通过文件 /sys/firmware/efi 确认启动模式:

[ -d /sys/firmware/efi ] && echo UEFI || echo BIOS

依据启动模式将 /etc/default/grub 生成到对应的 grub.cfg 中:

# BIOS
grub2-mkconfig -o /boot/grub2/grub.cfg

# UEFI
grub2-mkconfig -o /boot/efi/EFI/openEuler/grub.cfg

于是直接重启:

reboot

重启后可以检查一下 GRUB 配置是否生效:

cat /proc/cmdline

允许用户组分配大页

# 查询允许分配大页的用户组 ID
sysctl -n vm.hugetlb_shm_group

# 查询用户组 ID
id -g <group-name>

# 配置允许分配大页的用户组 ID
sysctl -w vm.hugetlb_shm_group=<group-id>

启用 openGauss 大页功能

修改 postgresql.conf

# 启用大页
enable_huge_pages = on

# 使用系统默认的大页大小
huge_page_size = 0

或者直接:

gs_guc set -D ${PGDATA} -c 'enable_huge_pages = on'
gs_guc set -D ${PGDATA} -c 'huge_page_size = 0'

需要重启数据库:

gs_ctl restart

注意,启用大页功能后,gaussdb 启动时会依据 GUC 参数 shared_buffers 指定的容量,尝试通过大页分配共享缓冲区,如果大页池容量不足会导致启动失败。 这时可以估算一下,扩大大页池容量就行。

关于透明大页

参考资料:

https://www.pingcap.com/blog/transparent-huge-pages-why-we-disable-it-for-databases/

上文介绍的标准大页需要单独管理,而透明大页可以在上层应用不感知的情况下使用大页分配内存。 在大部分情况下可以实现与标准大页类似的效果,在访问连续内存的场景下减少与页表相关的开销,从而获得更好的性能。 但透明大页需要将普通页合并为大页,会使得系统内核更频繁地触发内存回收与内存压缩,这会增加额外的开销。

  • 内存回收(memory reclaim)

    释放掉不必要的内存,涉及 I/O。 典型的场景有:将虚拟内存写回交换分区,随后将其释放;将映射文件的内存写回存储设备(仅脏页),随后释放。

  • 内存压缩(memory compaction)

    碎片整理,移动被占用的零碎页以获得足够大的连续空闲内存。

而数据库应用访问的内存是比较稀疏的,从大页获得的性能提升较少,于是透明大页带来的开销就变得无法接受了。 开启透明大页导致数据库性能问题时,通常会看到更高的 CPU 占用率。

查询当前透明大页配置:

# 控制透明大页是否开启
cat /sys/kernel/mm/transparent_hugepage/enabled

# 该参数用于控制内核是否更积极地执行内存压缩,便于在需要时提供更多的大页
cat /sys/kernel/mm/transparent_hugepage/defrag

关闭透明大页相关特性:

echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag