一、Hupe Page 定义
在 Linux 中,虚机内存是以页为单位来管理的。页的大小为 4KB。 1MB 的内存能划分为 256 页; 1GB 则等同于 256000 页。
CPU 中有一个内置的内存管理单元,用于存储这些页的列表(页表),每页都有一个对应的入口。
TLB(Translation lookaside buffer)为页表(存放虚拟地址的页地址和物理地址的页地址的映射关系)在CPU内部的高速缓存。TLB的命中率越高,页表查询性能就越好。
TLB的一行为一个页的映射关系,也就是管理了一个页大小的内存:TLB管理的内存大小 = TLB行数 x 内存的页大小
同一个CPU的TLB行数固定,因此内存页越大,管理的内存越大,相同业务场景下的TLB命中率就越高。
如果为服务器分配的内存远大于现有内存管理单元能管理的量,则会造成内存的浪费。 CentOS 6 中为解决这个问题,使用了大页面(Huge Page)的方式。
简单来说,大页面(Huge Page)即大小为 2MB 或者 1GB 的页。 2MB 的页适用于管理 GB 级单位的内存; 1GB 的页适用于 TB 级单位的内存。
大页面(Hupe Page)的配置
大页面配置需要连续的内存空间,因此在开机时就分配是最可靠的方式。配置大页面的参数有:
- hugepages :在内核中定义了开机启动时就分配的永久大页面的数量。默认为 0,即不分配。只有当系统有足够的连续可用页时,分配才会成功。由该参数保留的页不能用于其他用途。
hugepagesz: 在内核中定义了开机启动时分配的大页面的大小。可选值为 2MB 和 1GB 。默认是 2MB 。
default_hugepagesz:在内核中定义了开机启动时分配的大页面的默认大小。
1、开机时就分配方式: # cat /etc/default/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 rhgb quiet mgag200.modeset=0 transparent_hugepage=never default_hugepagesz=2M hugepagesz=2M hugepages=1024" GRUB_DISABLE_RECOVERY="true"
# grub2-mkconfig -o /boot/grub2/grub.cfg # reboot
2、动态设置方式: # echo never > /sys/kernel/mm/transparent_hugepage/enabled # echo 1024 > /proc/sys/vm/nr_hugepages # systemctl restart kubelet
# 验证是否生效,刚到HugePages_Total和HugePages_Free有值就生效了 # cat /proc/meminfo | grep -i huge AnonHugePages: 3534848 kB ShmemHugePages: 0 kB FileHugePages: 0 kB HugePages_Total: 1024 HugePages_Free: 1024 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB Hugetlb: 2097152 kB # cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages 512 # cat /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages 512 # cat /sys/devices/system/node/node1/hugepages/hugepages-1048576kB/nr_hugepages 0 # cat /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages 0 |
配置大页面后,系统在开机启动时会首选尝试在内存中找到并预留连续的大小为 hugepages * hugepagesz 的内存空间。如果内存空间不满足,则启动会报错 Kernel Panic, Out of Memory 等错误。
使用大页面后,能减少系统管理和访问页的时间;内核中的 swap 守护进程也不会管理大页面占用的这部分空间。合理设置大页面能减少内存操作的负担,减少访问页表造成性能瓶颈的可能性,从而提升系统性能。
注意:节点从普通内存分出一定大小来作为大页内存使用,所以节点分配了大页内存后,节点的普通内存总库存大小要减去大页内存的值,这个重启kubelet后node的Allocatable.Memory会自动减掉,只需要在OPS重新同步内存库存。
二、创建HugePage虚机
虚机要同时满足以下条件:
resources.limits.memory的值必须等于resources.requests.memory。
resources.requests.memory的值不能超过节点的2MB 或者 1GB 的页总大小(页总大小=hugepages * hugepagesz)。
如果选的页大小是2MB,resources.requests.memory的值必须可以整除2MB,如果选的页大小是1GB,resources.requests.memory的值必须可以整除1GB。
apiVersion: kubevirt.io/v1alpha3 kind: VirtualMachine metadata: labels: kubevirt.io/vm: huge-page-vm name: huge-page-vm # namespace: test spec: template: spec: domain: cpu: cores: 2 model: host-model resources: limits: cpu: "2" memory: 4Gi requests: cpu: 666m memory: 4Gi memory: # 设置hugepagesz是2Mi或1Gi hugepages: pageSize: "2Mi" |
virt-launcher的pod会占用多一点内存,所以huge-page虚机扣减库存多加1G大小。
注意:mem_huge_page_repo表更新allocate_memory时,mem__huge_page_sale表的记录插入时,allocate_request和allocate_limit的值应该比request和limit值大1G。
三、NUMA支持
NUMA简单可以理解为CPU的内存亲和性,在Linux内核2.5版本开始支持。不同NUMA内的CPU core访问同一个位置的内存,性能不同。内存访问延时从高到低为:跨CPU > 跨NUMA不跨CPU > NUMA内。
要开出NUMA的虚机,必须满足以下条件:
- 虚机必须是独占CPU的,虚机必须是Guaranteed级别。
- 节点必须配置了大页内存。
- kubevirt 版本是0.43以上,feature-gate必须打开NUMA特性。
apiVersion: kubevirt.io/v1alpha3 kind: VirtualMachine metadata: labels: kubevirt.io/vm: numa-vm name: numa-vm # namespace: test spec: template: spec: domain: cpu: dedicatedCpuPlacement: true isolateEmulatorThread: true numa: guestMappingPassthrough: { } resources: limits: cpu: 2 memory: 4Gi requests: cpu: 2 memory: 4Gi memory: # 设置hugepagesz是2Mi或1Gi hugepages: pageSize: "2Mi" |
kubevrit文档不建议domain.cpu和resources.cpu同时设置,我们统一使用resources设置cpu和内存即可。