Linux内核支持
linux虽然没有aix,hp unix那么强悍,但linux也是非常优秀的os。为了提升linux的性能,它采用了很多 io、memory的调度机制,linux使用内存的方式是采用vm的方式,即linux把物理内存和swap共同虚拟成可用内存来对外提供使用,有时用户看似使用内存,实则使用磁盘。
linux管理内存的单位是页(pages),一般情况下默认的 page size 为4k。显然,对于SGA比较大(SGA_MAX_SIZE > 8G )的数据库系统,管理这么大的内存会给系统造成很大的负担,再加上频繁的pagein/pageout,最终会成为系统的瓶颈。
Hugepages引入
hugepage是在linux2.6内核被引入的,其目的就是使用更大的 memory page size 以适应越来越大的系统内存管理。
Page Table是用来存放虚拟内存页和物理内存页映射关系的内存数据结构。当进程访问虚拟内存地址时,首先访问Page Table,然后再根据Page Table的映射关系mapping来访问真实物理内存地址(RAM+SWAP)。
(借用网络上的图示)
因为Linux默认的page size为4k,所以相应的 Page Table 内存结构会比较大。而Hugepages的常见page size为2M,是默认值4k的500倍,可以大大降低 Page Table 内存结构的大小。
接下来,引用两个例子,比较启用hugepages与否两者之间的区别。
例1:没有配置Hugepage的系统
$stat -f / | grep "Block size"
Block size: 4096 Fundamental block size: 4096
首先,先查看系统的block size大小。
$ cat /proc/meminfo
MemTotal: 132086880 kB
...
PageTables: 4059612 kB
可以看出,系统内存为128G,pagetable大小约为4G。
例2:配置了Hugepage的系统
$ cat /proc/meminfo
MemTotal: 98999880 kB
PageTables: 79916 kB
可以看出:系统内存为96G, PageTable大小仅为78M。
为了提升访问性能,在CPU cache中有一个固定大小的TLB(Transaction Lookaside Buffer),用来保存部分Page Table以提高虚拟地址的转换速度,遵循让数据尽可能的靠近CPU的原则。提高了TBL命中率,也就是提高了地址转换的速度。因为Page size变大了,所以同样大小的TLB,所覆盖的内存大小也变大了。
使用Hugepages的内存页是不会被交换出去的,永远常驻在内存中,所以也减少了内存页替换的额外开销
HugePages注意事项
下面再说说在数据库服务器上使用Hugepages要注意的几点
1. Hugepages是在分配后就会预留出来的,其大小一定要比服务器上所有实例的SGA总和要大,差一点都不行。
比如说Hugepages设置为90G,oracle SGA为91G,那么oracle在启动的时候就不会使用到这90G的Hugepages。这90G就浪费了。所以在设置Hugepages时要计算SGA的大小,后面会给出一个脚本来计算。
2. 其他进程无法使用Hugepages的内存,所以不要设置太大,稍稍比SGA大一点保证SGA可以使用到hugepages就好了。
3. PGA不会使用Hugepages的内存。所以11g的AMM (Automatic Memory Management,memory_target参数)是不被支持的。而ASMM(Automatic Shared Memory Management, SGA_target参数)是被支持的,这两个不要搞混淆了。
4. 在meminfo中和Hugepage相关的有四项
HugePages_Total
所分配的hugepages页面数目,和Hugepagesize相乘后得到所分配的内存大小;
HugePages_Free
从来没有被使用过的Hugepages数目。即使oracle sga已经分配了这部分内存,但是如果没有实际写入,那么看到的还是Free的;
HugePages_Rsvd
已经被分配预留但是还没有使用的page数目。在Oracle刚刚启动时,大部分内存应该都是Reserved并且Free的,随着oracle SGA的使用,Reserved和Free都会不断的降低;
Hugepagesize
默认的hugepages页大小,不可以修改;
HugePages_Free – HugePages_Rsvd 这部分是没有被使用到的内存,如果没有其他的Oracle instance,这部分内存也许永远都不会被使用到,也就是被浪费了。
开启HugePages并使数据库生效
开启大页HugePage步骤如下:
1、关闭Oracle Database 11g中的AMM(Automatic Memory Management),即把两个参数MEMORY_TARGET / MEMORY_MAX_TARGET设为0
另外:默认情况下ASM instance 也是使用AMM的,但因为ASM 实例不需要大SGA,所以对ASM 实例使用HugePages意义不大。
2、计算hugepages的参数值
Oracle默认提供hugepages计算脚本(/app/oracle/product/11.2.0/rdbms/admin/hugepages_settings.sh),执行之前对hugepages_settings.sh 这个脚本授可执行的权限
[oracle@mydb admin]$ chmod +x hugepages_settings.sh
然后,执行hugepages_settings.sh
[oracle@mydb admin]$ ./hugepages_settings.sh
...
...
Press Enter to proceed...
Recommended setting: vm.nr_hugepages = 1028
计算得到 hugepages 的推荐值为1028 页(注:一页为2M,这个值不可改,1028*2M=2056M),实际上hugepages与参数sga_max_size有关,比sga_max_size的值稍微大一点点(比SGA_MAX_SIZE最少要多加一页,2M的页不要分配超过sga_max_size太多,会造成内存的浪费)
3、设置hugepages,在内核参数中添加一行
[root@mydb ~]# vi /etc/sysctl.conf
vm.nr_hugepages = 1028
4、修改内核参数立即生效
[root@mydb ~]# sysctl -p
5、设定/etc/security/limits.conf文件,以K为单位,必须大于sga_max_size,这里设定为2056000
[root@mydb ~]# vi /etc/security/limits.conf
oracle soft memlock 2056000
oracle hard memlock 2056000
6、检查limits是否正确
[root@mydb ~]# su - oracle
[oracle@mydb ~]$ ulimit -l
2056000
7、重启数据库
注意:需要在原来的orale用户窗口退到root用户后,重新su - oracle切换到oracle用户,使配置生效。
[oracle@mydb ~]$ sqlplus / as sysdba
SQL> shutdown immediate;
SQL> startup
8、查看大页的使用情况
[oracle@mydb ~]$ watch -n1 'cat /proc/meminfo |grep -i HugePage'
Every 1.0s: cat /proc/meminfo |grep -i HugePage Thu Dec 5 11:09:06 2013
HugePages_Total: 1028
HugePages_Free: 869
HugePages_Rsvd: 842
注:
HugePages_Total: 1028 ---总共1028页
HugePages_Free: 869 ---空闲548页,即当前大页被使用了1028-869=159页,即被用了159*2M=118M,小于sga_target。
HugePages_Rsvd: 842 ---操作系统承诺给Oracle预留842页,即842*2M=1684M(1684+118==SGA_MAX_SIZE)
Hugepagesize: 2048 kB --每页是2M,不可修改
使用了hugepage之后,SGA就默认pin在内存里了,那么就不用lock sga了。
9、尝试启用 pre_page_sga 并查看效果
注意:参数 pre_page_sga 默认是false
SQL> alter system set pre_page_sga=true scope=spfile;
System altered.
sys@OCM> show parameter sga
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
lock_sga boolean FALSE
pre_page_sga boolean TRUE
sga_max_size big integer 2G
sga_target big integer 1G
HugePages_Total: 1028 ---总共1028页
HugePages_Free: 548 ---空闲548页,即当前大页被使用了1028-548=480页,即被用了480*2M=960M,约等于sga_target,参数pre_page_sga起作用了。
HugePages_Rsvd: 521 ---操作系统承诺给Oracle预留521页,即521*2M=1042M(理解为sga_max_size-sga_target)
Hugepagesize: 2048 kB --每页是2M,不可修改
附录:
系统缺省会启用 Transparent HugePages,用来提高内存管理的性能透明大页(Transparent HugePages ), THP 与Hugepages 类似,主要的区别是:Transparent HugePages 可以实时配置,不需要重启才能生效配置。
$cat /proc/meminfo | egrep 'Huge|MemTotal|PageTables'
MemTotal: 790965276 kB
PageTables: 1053188 kB
AnonHugePages: 208969728 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
只要这里 AnonHugePages 的值大于0,即表示启用了THP。
在linux 6.2 之后可以通过如下命令来监控THP。
$egrep 'trans|thp' /proc/vmstat
nr_anon_transparent_hugepages 102079
thp_fault_alloc 458782670
thp_fault_fallback 25986
thp_collapse_alloc 188918
thp_collapse_alloc_failed 0
thp_split 43215
thp_zero_page_alloc 1
thp_zero_page_alloc_failed 0
查看哪些进程在使用THP:
$grep -e AnonHugePages /proc/*/smaps | awk '{ if($2>4) print $0} ' | awk -F "/" '{print $0; system("ps -fp " $3)} '
因为 THP 会导致节点重启,所以Oracle 强烈建议关闭THP。