系统进程是通过虚拟地址访问内存,但是CPU必须把它转换程物理内存地址才能真正访问内存。为了提高这个转换效率,CPU会缓存最近的虚拟内存地址和物理内存地址的映射关系,并保存在一个由CPU维护的映射表中。为了尽量提高内存的访问速度,需要在映射表中保存尽量多的映射关系。
而在Linux中,内存都是以页的形式划分的,默认情况下每页是4K,这就意味着如果物理内存很大,则映射表的条目将会非常多,会影响CPU的检索效率。因为内存大小是固定的,为了减少映射表的条目,可采取的办法只有增加页的尺寸。
2. HugePages简介 2.1 相关概念HugePages是在Linux2.6内核被引入的,主要提供4k的page和比较大的page的选择。
概念
概念说明
page table
page table是操作系统上的虚拟内存系统的数据结构模型,用于存储虚拟地址与物理地址的对应关系。
当我们访问内存时,首先访问page table,然后Linux在通过page table的mapping来访问真实物理内存(ram+swap)
TLB
A Translation Lookaside Buffer (TLB)
TLB是在cpu中分配的一个固定大小的buffer(or cache),用于保存page table的部分内容,使CPU更快的访问并进行地址转换。
hugetlb
hugetlb 是记录在TLB 中的条目并指向Hugepages。
hugetlbfs
这是一个新的基于2.6 kernel之上的内存文件系统,如同tmpfs。
在TLB中通过hugetlb来指向hugepage。这些被分配的hugepage作为内存文件系统hugetlbfs(类似tmpfs)提供给进程使用。
2.2 使用HugePages的意义
HugePages是Linux内核的一个特性,使用hugepage可以用更大的内存页来取代传统的4K页面。使用HugePage主要带来以下好处:
1. HugePages 会在系统启动时,直接分配并保留对应大小的内存区域。
2. HugePages 在开机之后,如果没有管理员的介入,是不会释放和改变的。
3. 没有swap。
Notswappable: HugePages are not swappable. Therefore thereis no page-in/page-outmechanism overhead.HugePages are universally regarded aspinned.
4. 大大提高了CPU cache中存放的page table所覆盖的内存大小,从而提高了TLB命中率。
进程的虚拟内存地址段先连接到page table然后再连接到物理内存。所以在访问内存时需要先访问page tables得到虚拟内存和物理内存的映射关系,然后再访问物理内存。
CPU cache中有一部分TLB用来存放部分page table以提高这种转换的速度。因为page size变大了,所以同样大小的TLB,所覆盖的内存大小也变大了。提高了TLB命中率,也提高了地址转换的速度。
5. 减轻page table的负载。
进行XXX系统性能测试时,如果没有使用HugePages,数据库服务器上的pagetable大小大约为5G(这应该也是导致性能测试时数据库服务器内存不足的主要原因):
node74:/home/Oracle # cat /proc/meminfo
MemTotal: 16323732 kB
PageTables:
配置了HugePages后,pagetable大小仅为124M(性能测试时内存使用率稳定在80%左右):
node74:/home/oracle # cat /proc/meminfo
MemTotal: 16323732 kB
PageTables:
Eliminated page tablelookup overhead: 因为hugepage是不swappable的,所有就没有page table lookups。
Faster overall memory performance: 由于虚拟内存需要两步操作才能实际对应到物理内存地址,因此更少的pages,减轻了page table访问热度,避免了page table热点瓶颈问题。
6. 提高内存的性能,降低CPU负载,原理同上
2.3 使用HugePages需要注意的地方
1. Hugepages是在分配后就会预留出来的,其大小一定要比服务器上所有实例的SGA总和要大,差一点都不行。
比如说Hugepages设置为8G,oracle SGA为9G,那么oracle在启动的时候就不会使用到这8G的Hugepages。这8G就浪费了。所以在设置Hugepages时要计算SGA的大小,后面会给出一个脚本来计算。
2. 其他进程无法使用Hugepages的内存,所以不要设置太大,稍稍比SGA大一点保证SGA可以使用到hugepages就好了。
3. 在meminfo中和Hugepage相关的有四项:
HugePages_Total: 4611
HugePages_Free: 474
HugePages_Rsvd: 467
Hugepagesize: 2048 kB
HugePages_Total为所分配的页面数目,和Hugepagesize相乘后得到所分配的内存大小。4611*2/1024大约为9GB
HugePages_Free为从来没有被使用过的Hugepages数目。即使oraclesga已经分配了这部分内存,但是如果没有实际写入,那么看到的还是Free的。这是很容易误解的地方。
HugePages_Rsvd为已经被分配预留但是还没有使用的page数目。在Oracle刚刚启动时,大部分内存应该都是Reserved并且Free的,随着oracle SGA的使用,Reserved和Free都会不断的降低。
HugePages_Free-HugePages_Rsvd 这部分是没有被使用到的内存,如果没有其他的oracle instance,这部分内存也许永远都不会被使用到,也就是被浪费了。
4. HugePages和oracle AMM(自动内存管理)是互斥的,所以使用HugePages必须设置内存参数MEMORY_TARGET / MEMORY_MAX_TARGET 为0。
3. 配置HugePages
3.1 修改内核参数memlock
修改内核参数memlock,单位是KB,如果内存是16G,memlock的大小要稍微小于物理内存。计划lock 12GB的内存大小。参数设置为大于SGA是没有坏处的。
以root用户登录两台数据库服务器,编辑limits.conf文件:
node74:~ # vi /etc/security/limits.conf
增加以下两行内容:
* soft memlock 12582912
* hard memlock 12582912
3.2 验证memlock limit
重新登录root和oracle用户,检查memlocklimit
node74:~ # ulimit -l
12582912
oracle@node74:~> ulimit -l
12582912
3.3 禁用AMM
如果使用11G及以后的版本,AMM已经默认开启,但是AMM与Hugepages是不兼容的,必须先disable AMM。禁用AMM的步骤如下:
3.3.1 关闭数据库实例
已oracle用户登录两台数据库服务器,通过sqlplus关闭2个数据库实例。
oracle@node74:~> sqlplus / as sysdba
SQL> shutdown immediate
3.3.2 创建pfile
以oracle用户登录其中一台主机,执行以下命令创建pfile:
oracle@node74:~> sqlplus / as sysdba
SQL> create pfile='/home/oracle/pfile.ora' fromspfile=’+DG_ORA/orcl/spfileorcl.ora’;
3.3.3 编辑pfile
编辑pfile,删除memory_max_target和memory_target参数:
oracle@node74:~> vi /home/oracle/pfile.ora
删除下面几行:
orcl1.memory_max_target=11114905600
orcl2.memory_max_target=11114905600
*.memory_max_target=0
orcl1.memory_target=11114905600
orcl2.memory_target=11114905600
*.memory_target=0
修改后保存文件。
3.3.4 创建spfile
执行以下命令创建spfile:
oracle@node74:~> sqlplus / as sysdba
SQL> create spfile='+DG_ORA/orcl/spfileorcl.ora'from pfile='/home/oracle/pfile.ora';
3.3.5 修改系统参数kernel.shmall
Kernel.shmall是系统一次可以使用的最大共享内存大小。单位是page(4KB)。禁用AMM后,需要修改系统参数kernel.shmall,该参数设置过小的话,可能会导致数据库启动失败ORA-27102(详见附录4.2)。
ORACLE建议将其设置为系统中所有数据库实例的SGA总和。例如SGA总和为9GB,则需要设置kernel.shmall=9*1024*1024/4=2359296。
以root用户登录两台数据库服务器,编辑sysctl.conf文件。
node74:~ # vi /etc/sysctl.conf
修改kernel.shmall参数:
kernel.shmall = 2359296
执行sysctl –p使配置生效:
node74:~ # sysctl -p
3.3.6 启动数据库实例
以oracle用户登录两台数据库服务器,通过sqlplus启动2个数据库实例。
oracle@node74:~> sqlplus / as sysdba
SQL> startup
3.4 计算需要使用的hugepage页面大小
确保全部实例都已经启动(包括ASM) ,然后以root用户运行hugepages_settings.sh(脚本内容见附录4.1)去评估需要设置的Hugepages的大小。
node74:/home/oracle # ./hugepages_settings.sh
This script is provided by Doc ID 401749.1 from MyOracle Support
(http://support.oracle.com) where it is intended tocompute values for
the recommended HugePages/HugeTLB configuration forthe current shared
memory segments. Before proceeding with the executionplease make sure
that:
* OracleDatabase instance(s) are up and running
* OracleDatabase 11g Automatic Memory Management (AMM) is not setup
(See Doc ID749851.1)
* The sharedmemory segments can be listed by command:
# ipcs -m
Press Enter toproceed...
----直接按Enter键
Recommended setting: vm.nr_hugepages = 4611
也可以手工计算:
nr_hugepages>=SGA_Target/Hugepagesize
=9G*1024M/2M
=4608
取一个比4608稍大的值即可。
3.5 修改vm.nr_hugepages参数
以root用户登录两台数据库服务器,编辑/etc/sysctl.conf:
node74:~ # vi /etc/sysctl.conf
修改vm.nr_hugepages参数为上一步中计算出来的值:
vm.nr_hugepages = 4611
执行sysctl –p使配置生效:
node74:~ # sysctl -p
3.6 停止数据库实例,重启操作系统
停止所有数据库实例,重启操作系统。(理论上不需要重启操作系统,建议重启)
3.7 检查设置是否生效
系统重启后,启动全部的数据库,通过以下命令检查配置是否生效:
node74:~ # grep HugePages /proc/meminfo
HugePages_Total: 4611
HugePages_Free: 2394
HugePages_Rsvd: 2387
HugePages_Surp: 0
HugePages_Free< HugePages_Total则说明Hugepages已经生效,同时HugePages_Rsvd不为0。
4. 附录 4.1 脚本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.
#
# This script is provided by Doc ID 401749.1 from My Oracle Support
# http://support.oracle.com
# Welcome text
echo "
This script is provided by Doc ID 401749.1 from My Oracle Support
(http://support.oracle.com) where it is intended to compute values for
the recommended HugePages/HugeTLB configuration for the current shared
memory segments. Before proceeding with the execution please make sure
that:
* Oracle Database instance(s) are up and running
* Oracle Database 11g Automatic Memory Management (AMM) is not setup
(See Doc ID 749851.1)
* The shared memory segments can be listed by command:
# ipcs -m
Press Enter to proceed..."
read
# Check for the kernel version
KERN=`uname -r | awk -F. '{ printf("%d.%dn",$1,$2); }'`
# Find out the HugePage size
HPG_SZ=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
# Initialize the counter
NUM_PG=0
# 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
RES_BYTES=`echo "$NUM_PG * $HPG_SZ * 1024" | bc -q`
# An SGA less than 100MB does not make sense
# Bail out if that is the case
if [ $RES_BYTES -lt 100000000 ]; then
echo "***********"
echo "** ERROR **"
echo "***********"
echo "Sorry! There are not enough total of shared memory segments allocated for
HugePages configuration. HugePages can only be used for shared memory segments
that you can list by command:
# ipcs -m
of a size that can match an Oracle Database SGA. Please make sure that:
* Oracle Database instance is up and running
* Oracle Database 11g Automatic Memory Management (AMM) is not configured"
exit 1
fi
# 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') echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;;
*) echo "Unrecognized kernel version $KERN. Exiting." ;;
esac
# End
Upon startup of Linux database getORA-27102: out of memory Linux-X86_64 Error: 28: No space left on device
Subject:
Upon startup of Linux database getORA-27102: out of memory Linux-X86_64 Error: 28: No space left on device
Doc ID:
Note:301830.1
Type:
PROBLEM
Last Revision Date:
31-OCT-2008
Status:
PUBLISHED
In this Document
Symptoms
Changes
Cause
Solution
References
--------------------------------------------------------------------------------
Applies to:
OracleServer- Enterprise Edition - Version: 9.2.0.4 to 11.1.0.6
UnitedLinux x86-64
Red Hat Enterprise Linux Advanced Serverx86-64 (AMD Opetron Architecture)
x86 64 bit
Symptoms
When trying to increase the SGA to approachhalf available RAM with an Oracle 64bit version on a Linux 64bit operatingsystem, even though shmmax is set to match half the amount of RAM, youget the following error when trying to start the instance:
SQL> startup nomount
ORA-27102: out of memory
Linux-x86_64 Error: 28: No space left ondevice
Changes
shmall is too small, most likely is set tothe default setting of 2097152
$ cat /proc/sys/kernel/shmall
2097152
Cause
shmall is the total amount of sharedmemory, in pages, that the system can use at one time.
Solution
Set shmall equal to the sum of all the SGAson the system, divided by the page size.
The page size can be determined using thefollowing command:
$ getconf PAGE_SIZE
4096
For example, if the sum of all the SGAs onthe system is 16Gb and the result of '$ getconf PAGE_SIZE' is 4096 (4Kb)then set shmall to 4194304 (4Mb)
As the root user set the shmall to 4194304in the /etc/sysctl.conf file:
kernel.shmall = 4194304
then run the following command:
# sysctl –p
# cat /proc/sys/kernel/shmall
4194304
NOTE:
The above command loads the new value and areboot is not necessary
Switch back to being the oracle user andretry the startup command.
References
Note 169706.1 - Oracle? Database onAIX?,HP-UX?,Linux?,Mac OS? X,Solaris?,Tru64 Unix? Operating SystemsInstallation and Configuration Requirements Quick Reference (8.0.5 to 11.1)
Keywords
NO~SPACE~LEFT~ON~DEVICE ; START~INSTANCE ;OUT~OF~MEMORY ; 64BIT ;
: