一、概念:
Oracle 数据库和 Linux 内存管理
系统中使用的内存越多,管理该内存所需的资源也就越多。对于 Linux 操作系统,通过 Linux kswapd 进程和页表内存结构(针对系统中存在的每个进程包含一条记录)实现内存管理。每条记录包含进程使用的每页虚拟内存及其物理地址(RAM 或磁盘)。通过使用处理器的转换旁路缓冲区(TLB,一小块缓存)为该进程提供帮助。
当大量内存用于 Oracle 数据库时,操作系统将消耗大量资源来管理虚拟地址到物理地址转换,其结果往往是一个非常大的页表结构。由于每条页表条目包含进程正在使用的所有内存页面的虚拟地址到物理地址的转换,因此对于非常大的系统全局区 (SGA),每个进程的页表条目都可能很大。例如,使用 8 GB 内存的 Oracle 数据库进程的页表条目将达 8 GB/4 KB(即 2097152 条记录或页面)。如果有 100 个 Oracle 数据库会话/进程,则将页面数乘以 100。您可以看到,要管理的页面数量巨大。
同样,操作系统使用页表条目管理系统中进程所用的内存。在 Linux 中,执行此管理的操作系统进程被称作 kswapd,可在操作系统工具中找到。
TLB 缓存将缓存页表条目来提高性能。典型的 TLB 缓存可保存 4 到 4096 个条目。对于数百万甚至数十亿个页表条目,这种缓存就不够用了。
如上所述,对于使用大型 SGA 的系统,页表结构可能会变得非常大。清单 1 中的 Linux 系统输出示例显示页表条目占用了 766 MB 的 RAM。这可能导致显著的系统开销。我亲眼见过数 GB 的页表条目。
HugePages 是 Linux 操作系统的一个内核特性,让操作系统可以支持现代硬件架构的大页面容量功能。对于 Oracle 数据库,通过启用 HugePages 并使用大页面,可以用一个页表条目代表一个大页面,而不是使用许多条目代表较小的页面,从而可以管理更多内存,减少操作系统对页面状态的维护并提高 TLB 缓存命中率。在 Linux 中,大页面大小为 2 MB。
在 Oracle Linux 6 或 Red Hat Enterprise Linux 6 (RHEL 6) 中,可在 /proc/meminfo 中找到分配的 HugePages 数,如清单 1 所示:
[root@ptc1 ~]# cat /proc/meminfo
MemTotal: 4045076 kB
MemFree: 14132 kB
Buffers: 656 kB
Cached: 1271560 kB
SwapCached: 6184 kB
Active: 2536748 kB
Inactive: 625616 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 4045076 kB
LowFree: 14132 kB
SwapTotal: 1052216 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
Mapped: 2036576 kB
Slab: 49712 kB
CommitLimit: 3074752 kB
Committed_AS: 8054664 kB
PageTables: 766680 kB
VmallocTotal:536870911 kB
VmallocUsed: 263168 kB
VmallocChunk:536607347 kB
HugePages_Total: 0
HugePages_Free: 0
Hugepagesize: 2048 kB
清单 1
在 Oracle Linux 6 中,分配的 HugePages 略有不同,如清单 2 所示:
AnonHugePages: 0 kB
HugePages_Total: 1508
HugePages_Free: 60
HugePages_Rsvd: 57
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 10240 kB
DirectMap2M: 16766976 kB
清单 2
Oracle Linux 6 HugePages 值如下所示:
* `AnonHugePages`。匿名 HugePages 数量。Oracle Linux 6.5 中已删除此计数器。与透明 HugePages 有关。(有关透明 HugePages 的详细信息,请参见“[透明 HugePages 和 Oracle 数据库](https://www.oracle.com/cn/technical-resources/articles/it-infrastructure/dev-hugepages.html#trans)”一节。)
* `HugePages_Total`。HugePages 数量。空间大小为 HugePages 数乘以 2M。
* `HugePages_Free`。池中尚未分配的 HugePages 数量。
* `HugePages_Rsvd`。“reserved”的缩写形式,表示池中已经承诺分配但尚未分配的 HugePages 数量。保留的 HugePages 保证应用程序随时请求都能够从 HugePages 池分配 HugePages,即使系统已经运行一段时间。
* `HugePages_Surp`。“surplus”的缩写形式,表示池中大于 `/proc/sys/vm/nr_hugepages` 中值的 HugePages 数量。剩余 HugePages 的最大数量由 `/proc/sys/vm/nr_overcommit_hugepages` 控制。此值为 `0` 的情况很常见。
* `Hugepagesize`。HugePage 的大小。此参数当前为 2048 或 2 MB。
二、解决方案
通过在 Linux 中启用 HugePages,可以通过增大页面大小来减少 TLB 条目数。对于 Linux,HugePages 大小为 2 MB。通过为 Oracle 数据库 SGA 选用更大的页面,可大大减少要管理的页面数。
1、控制SGA大小, sga+pga最好控制在50%物理内存以内,pga内存不要操作sga内存的20%;
2、当主机的物理内存为64G,设SGA>=32G时,建议开启大页;
内存都是以页的形式划分的,默认情况下每页是4K,这就意味着如果物理内存很大,则映射表的条目将会非常多,会影响CPU的检索效率。因为内存大小是固定的,为了减少映射表的条目,可采取的办法只有增加页的尺寸。
在清单 1 所示示例中,单条记录的虚拟地址到物理地址转换数将从 2097152 减少至 4096。这将减小页表结构的大小,提高 TLB 命中率,并降低 kswapd 使用率。
注:启用 HugePages 可显著提升性能。
在 Linux 中启用 HugePages
在 Linux 中,通过将 Linux 初始化参数 vm.nr_hugepages 设置为您希望为 Oracle 数据库 SGA 提供的 2 MB 页面数来配置 HugePages 功能。设置此参数可通过将其值调大来减少页面数。
注:Oracle Database 11g 中引入的 Oracle 数据库自动内存管理特性与 Linux HugePages 不兼容。HugePages 提供的性能改进优于自动内存管理所提供的易用性。
有关如何实现 HugePages 配置的详细信息,可在表 1 所示的 My Oracle Support 文档中找到。
除了配置 vm.nr_hugepages,还可以将可选的 vm.hugetlb_shm_group 参数设置为有权使用 HugePages 的操作系统组。默认情况下,此参数设置为 0,从而允许所有组使用 HugePages。可以将此参数设置为 Oracle 数据库进程所属的操作系统组,如 oinstall。
验证是否已对 Oracle 数据库实例启用大页面
可以通过检查警报日志来验证是否对数据库实例启用了大页面。启动实例时,您应在警报日志中参数列表前面看到如下内容:
****************** Large Pages Information *****************
Total Shared Global Region in Large Pages = 28 GB (100%)
Large Pages used by this instance: 14497 (28 GB)
Large Pages unused system wide = 1015 (2030 MB) (alloc incr 64 MB)
Large Pages configured system wide = 19680 (38 GB)
Large Page size = 2048 KB
透明 HugePages 和 Oracle 数据库
最近,RHEL 6、Oracle Linux 6 和 SUSE Linux Enterprise Server 11 中引入了一个新特性 - 透明 HugePages。透明 HugePages 旨在自动、动态地利用 HugePages。遗憾的是,目前透明 HugePages 与传统 HugePages 联用会出现一些问题,导致性能问题和系统重启。在 My Oracle Support 说明 1557478.1 中,Oracle 建议不要同时使用透明 HugePages 和 Oracle 数据库。
注:在 Oracle Linux 6.5 版中,已删除透明 HugePages。
总结
通过使用更大的页面,可以减少页表条目数,从而最大程度减少开销。使用 HugePages 可显著提升性能,增加系统中的内存数量和 SGA 大小。
三、 具体过程
1、关闭Oracle Database 11g中的AMM(Automatic Memory Management),
即把两个参数MEMORY_TARGET / MEMORY_MAX_TARGET设为0
如果alter system set MEMORY_MAX_TARGET=0 scope=spfile;重启后发现没有改为0,可以alter system reset memory_max_target; 来设置
禁用AMM特性須要將memory_max_target, memory_max_target2個參數重置,而不能過設置為0。最好的辦法是創建一個pfile,在pfile中將這2個參數刪除,再依據這個pfile創建spfile.
2、参考metalink(文档 ID 401749.1)提供的脚本,计算hugepages的大小
3、对hugepages_settings.sh这个脚本授可执行的权限
chmod +x hugepages_settings.sh
4、执行执行hugepages_settings.sh得到建议值
#!/bin/bash
#
# hugepages_settings.sh
#
# Linux bash script to compute values for the
# recommended HugePages/HugeTLB configuration
#
# Note: This script does calculation for all shared memory
# segments available when the script is run, no matter it
# is an Oracle RDBMS shared memory segment or not.
# Check for the kernel version
KERN=`uname -r | awk -F. '{ printf("%d.%d\n",$1,$2); }'`
# Find out the HugePage size
HPG_SZ=`grep Hugepagesize /proc/meminfo | awk {'print $2'}`
# Start from 1 pages to be on the safe side and guarantee 1 free HugePage
NUM_PG=1
# Cumulative number of pages required to handle the running shared memory segments
for SEG_BYTES in `ipcs -m | awk {'print $5'} | grep "[0-9][0-9]*"`
do
MIN_PG=`echo "$SEG_BYTES/($HPG_SZ*1024)" | bc -q`
if [ $MIN_PG -gt 0 ]; then
NUM_PG=`echo "$NUM_PG+$MIN_PG+1" | bc -q`
fi
done
# Finish with results
case $KERN in
'2.4') HUGETLB_POOL=`echo "$NUM_PG*$HPG_SZ/1024" | bc -q`;
echo "Recommended setting: vm.hugetlb_pool = $HUGETLB_POOL" ;;
'2.6'|'3.8') echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;;
*) echo "Unrecognized kernel version $KERN. Exiting." ;;
esac
# End
得出大页的大小为1028页(注:一页为2M,这个值不可改,1028*2M=2056M),实际上hugepages与参数sga_max_size有关,比sga_max_size的值稍微大一点点(比SGA_MAX_SIZE最少要多加一页,2M的页不要分配超过sga_max_size太多,会造成内存的浪费)
注意:使用Hugepage内存是共享内存,它会一直keep在内存中的,不会被交换出去,也就是说使用hurgepage的内存不能被其他的进程使用,所以,一定要合理设置这个值,避免造成浪费。对于只使用Oracle的服务器来说,把Hugepage_pool设置成大于SGA大小才能被Oracle使用。
SQL>show parameter sga_max_size
NAME TYPE VALUE
sga_max_size big integer 2G
5、设置hugepages,在内核参数中添加一行,vi /etc/sysctl.conf
vm.nr_hugepages = 1028
6、修改内核参数立即生效
[root@el5 ~]# sysctl -p
[email protected] ~]# grep -i huge /proc/meminfo
AnonHugePages: 602112 kB
HugePages_Total: 30739
HugePages_Free: 30739
HugePages_Rsvd: 0
HugePages_Surp: 0
7、别忘记设定内存锁memlock,以K为单位,memlock数量要大于大页的数量,当然也要大于sga_max_size,这里设定为2056000,设置为-1,表示不限制。
[root@el5 ~]# vi /etc/security/limits.conf
oracle soft memlock 2056000
oracle hard memlock 2056000
* Soft memlock 稍小於RAM值
* hard memlock 稍小於RAM值
Memlock值大於sga沒關系的,所以我們能夠設置這個值在我們想要的SGA size和物理內存size之間,這個值得單位是kb。
[[email protected] ~]# grep -i memtot /proc/meminfo
MemTotal: 132250576 kB
8、检查limits是否正确
[root@el5 ~]# su - oracle
[oracle@el5 ~] ulimit -l
2056000
9、重启数据库
10、查看大页,已被使用
[oracle@el5 ~]$ watch -n1 'cat /proc/meminfo |grep -i HugePage'
HugePages_Total: 总共页
HugePages_Free: 空闲页
HugePages_Rsvd: 操作系统承诺给Oracle预留页
Hugepagesize: 2048 kB 每页是2M,不可修改
如:
HugePages_Total: 1028 ---总共1028页
HugePages_Free: 869 ---空闲869 页,即当前大页被使用了1028-869=159页,即被用了1592M=118M,小于sga_target。
HugePages_Rsvd: 842 ---操作系统承诺给Oracle预留842页,即8422M=1684M(1684+118==SGA_MAX_SIZE)
使用了hugepage之后,SGA就默认pin在内存里了,那么就不用lock sga了。接下来我们研究一下参数:pre_page_sga,这个参数默认是false,我把它打开。
sys@OCM> alter system set pre_page_sga=true scope=spfile;
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页,即被用了4802M=960M,约等于sga_target,参数pre_page_sga起作用了。
HugePages_Rsvd: 521 ---操作系统承诺给Oracle预留521页,即5212M=1042M(理解为sga_max_size-sga_target)
Hugepagesize: 2048 kB --每页是2M,不可修改
参考metalink:USE_LARGE_PAGES To Enable HugePages (文档 ID 1392497.1)
补充关于内存申请的OverCommit
Linux下的OverCommit机制,主要是为了应对可能的异常的大量内存申请对OS本身造成冲击。
Linux有三种OverCommit机制,可以通过:/proc/sys/vm/overcommit_memory来配置,三种配置的具体含义:
0:启发式策略,后果比较严重的Overcommit将不能成功,而轻微的Overcommit将被允许。
1:永远允许Overcommit,这种策略适合那些不能承受内存分配失败的应用,比如某些科学计算应用。
2:永远禁止Overcommit,在这个情况下,系统所能分配的内存不会超过swap+RAM*系数(/proc/sys/vm /overcmmit_ratio,默认50%,你可以调整),如果这么多资源已经用光,那么后面任何尝试申请内存的行为都会返回错误,这通常意味着此时 没法运行任何新程序。
## 另请参见
* [性能调优网站](http://www.perftuning.com/)
* [Ed Whalen 的博客](http://www.perftuning.com/author/ewhalen/)
* [Ed Whalen 的 Twitter](https://twitter.com/etwhalen)
## 关于作者
Edward Whalen 是 Oracle ACE 并且是 Performance Tuning Corporation 的首席技术专家,Performance Tuning Corporation 是一家咨询公司,在数据库性能、管理、迁移、虚拟化和灾难恢复解决方案方面拥有超过 25 年的专业经验。他在通过系统架构设计实现最佳性能方面有着丰富经验。其职业生涯涉及许多不同公司的硬件、操作系统、数据库和虚拟化项目。Edward 编写过 6 本关于 Oracle 产品的书和 5 本关于 Microsoft SQL Server 的书,他还刚刚为 Oracle Press 完成了《Oracle Enterprise Manager Cloud Control 12c Deep Dive》一书。他还参与过许多基准测试和性能调优项目,既涉及 Oracle 产品,又涉及 Microsoft SQL Server。
Edward 具有丰富的架构经验,包括云/应用程序体系所有层面,从存储和硬件到虚拟机管理程序和操作系统,再到数据库。这些经验为他过去从事的系统架构工作奠定了坚实的基础。
Edward 最初作为实验物理学家在费米实验室和斯坦福线性加速器中心从事高能物理研究项目。在短暂从事超导超级对撞机工作之后,他转移到计算机软件领域,然后涉足计算机硬件和操作系统开发,最终转入数据库性能工程。