Oracle Memory Management and HugePage (连载一)

作者:沃趣科技高级数据库工程师  魏兴华 




概述

大家好,我是魏兴华,你们可以叫我肉丝,我的英文名是Rose魏。在这篇文章中,我给大家介绍一些Oracle内存管理和大页的知识。Oracle发展这么多年,提供了多种的内存管理方式,从最早SGAPGA手工管理,到9I版本出现的PGA的自动管理,到10G版本出现的SGA自动管理(ASMM),再到11G版本出现的memory自动管理(AMM)Oracle基本是在朝着智能化、傻瓜化、自动化的方向稳步前进着,对于初学OracleDBA来说,看到这些不同的内存管理方式一定心里有着不同程度的疑惑,例如:

·          Oracle有这么多内存分配的管理方式,我该使用哪一种?是使用11G版本推出的AMM管理方式,还是使用10G版本出现的ASMM管理方式?或者干脆使用最旧的手工方式管理内存?


·         我该为我的实例SGAPGA分别设置多大呢?

·         我该为buffer cacheshared pool分配多大的内存空间?

·         什么情况下我该使用大页?为什么大页这个词最近几年这么容易听到?
·         有没有一些简单粗暴的算法来搞定这一切?

写这篇文章的初衷也来源于上面这些非常正常的疑问,如果这篇文章能给有这些疑惑的DBA朋友一些指导和帮助,那肉丝我也就真的功莫大焉了。


Memory
构成

在一个运行着Oracle数据库的专用服务器上,内存基本上被以下内容所占用:
·               Kernel
·               OS Page Table
·               文件系统Cache
·               SGA
·               PGA
·               Oracle进程
·              其他进程(RMAN,非Oracle的进程等等)


严格来说OS Page Table也算是Kernel Memory部分的内容,由于本文后面会重点讲大页的内容,因此把OS Page Table这部分在图中独立了出来,以引起读者注意。必须要强调,Oracle不应该使用掉主机上的所有内存,过量的内存分配会诱发操作系统SWAP的产生,导致Oracle性能严重降低,在RAC环境下,内存不足还非常容易导致RAC节点的驱逐。对于Oracle两大块内存:SGAPGADBA一定要仔细根据系统特点、业务使用特点做好规划和设计,以防出现OS内存不够用的情况。

内存自动化发展历程
我们首先了解一下Oracle内存发展的历程,基本上Oracle的内存管理在版本的演进过程中沿着越来越智能化、自动化、傻瓜化的方向前进。接触过MYSQL等数据库的DBA朋友应该比较清楚,这些数据库基本上都还需要DBA去决定每个内存组件的大小,而Oracle已经从9I版本开始就迈向智能化、自动化的过程了。下图是Oracle内存管理的一个演进图:

PGA 自动管理

Oracle是多进程的架构,这点区别于MYSQLMYSQL是单进程多线程的架构,Oracle会为每一个用户连接创建一个独立的操作系统进程来为用户提供服务,这个进程叫做服务器进程或者影子进程,它像是用户的一个代理,来操作数据文件或者SGA内存,由于服务器进程的代码是Oracle公司开发的,所以Oracle公司完全相信这些进程或代码是安全的,因此这些进程可以直接操作数据文件和SGA内存,这些进程接受用户进程发送的指令,并完成相关的操作,并根据需要来给用户进程返回结果。由于服务器进程是操作系统上的一个进程,因此它本身需要占用一些操作系统内存,除此之外,进程在对数据进行读取、排序、hash过程中,也会占用一定量的内存,在Oracle 9I版本之前,对于服务器进程的内存管理是由一些参数去控制的,以下参数代表每一个服务器进程可以使用的不同区域的内存大小(都是进程的私有内存区域):
·         SORT_AREA_SIZE
·         HASH_AREA_SIZE
·         BITMAP_MERGE_AREA_SIZE
·         CREATE_BITMAP_AREA_SIZE
例如,SORT_AREA_SIZE控制了每一个进程可用的排序区大小,HASH_AREA_SIZE参数控制了每一个进程可用的hash区大小,这些参数都有默认值,但是默认值是否合适,需要打上一个大大的问号,因为不同的任务对于PGA内存的不同区域有不同的要求,例如,如果是做排序操作,就对排序区内存要求较大,而对hash区没任何的要求。当然如果默认值不合适,DBA可以手工调整这些区域的大小。

Oracle 9I版本出现了PGA的自动管理,不再需要像9I之前版本需要设置一系列参数来控制PGA的使用,只需要设置PGA_AGGREGATE_TARGET为一个值,就可以控制所有的服务器进程的PGA使用量,至于每个服务器进程使用了多少排序区,hash区,都交给Oracle去控制。


一般情况下对于PGA的大量使用有如下几种操作:
·         hash 对于hash join操作,hash桶所占用的内存就在进程的私有PGA内存中,而不是在共享内存SGA中,如果使用PGA手工管理的话,可以通过HASH_AREA_SIZE参数来动态调整会话进行hash操作能够使用的内存量。
·          sort 对于排序操作,例如查询语句里的order by、创建索引的排序操作等占用的内存也在PGA中,如果使用PGA手工管理,可以通过SORT_AREA_SIZE参数动态调整会话排序操作可以使用的内存量。
·         parallel 并行操作简直可以说是PGA内存的杀手,每一个并行进程都能使用到最多2GPGA内存,当然Oracle会确保所有的并行slave使用的PGA内存不能超过PGA_AGGREGATE_TARGET的一半。

现在Oracle的版本已经出到了12CPGA的自动管理已经发展了很多个年头,如果是个人,也应该是一个非常成熟的小伙子了,甚至是位大叔了????,绝大部分数据库操作完全没必要再去手工调整PGA的一些参数。不过,我们依然能从互联网上、论坛上看到有很多DBA对这种手工调整PGA的技术崇拜有加(我以前也是),确实在一些情况下,通过手工调整PGA的相关内存区,可以达到加速排序等一些操作的目的,但是如果需要操作的数据量非常的大,那这种调整往往是费时费力,甚至是徒劳的,因为对于一个进程的私有PGA内存来说,像sort,hashP区域的内存分配是有限制的,现在11GR2的版本对于每个进程的PGA内存最大限制默认是2G,且排序区可以使用的只有1G,如果你的排序等操作需要的内存远远不止12G,那么这种优化就非常的徒劳,甚至还可能变慢(肉丝亲身遭遇过变慢的案例????)。是否使用PGA自动管理由参数WORKAREA_SIZE_POLICY控制,它的值可以为automanual,顾名思义,autoPGA自动管理,manualPGA手工管理,回到9I之前的使用方式。


这里肉丝提供几个大家可能会感兴趣的隐含参数,比如我上面提到了每个进程最大能使用的PGA不能超过2G,通过修改隐含参数可以突破这个限制。 >肉丝在这里警戒各位,这些参数如果要在生产环境使用,请在你的数据库版本下做好测试。
以下为11GR2版本的情况,其他版本并未做测试:
·         _PGA_MAX_SIZE 每个进程的PGA的最大内存大小。默认值为:21474836482G,单位为B
·         _SMM_MAX_SIZE 每个进程的工作区的大小,默认值为1/2 _PGA_MAX_SIZE1048576 ,单位KB1GB,排序区、hash区都属于工作区的范围。64位系统下真实使用的排序区内存不能超过4GB
·         _SMM_PX_MAX_SIZE 所有并行查询的SLAVE进程能够用到的PGA总量。默认值为 1/2 pga_aggregate_target,单位为KBRAC环境下,每个节点都可以用到这么多内存。

以上全部为动态参数,可以在session/system级别来在线修改。
alter system set"_SMM_PX_MAX_SIZE"=10485760; 
alter system set"_SMM_MAX_SIZE"=1048576;
alter system set"_PGA_MAX_SIZE"=2147483648;

上面的参数调整后,一定要设置对应的pga_aggregate_target,否则以上调整可能会不起作用,建议设置为修改后的_SMM_PX_MAX_SIZE的值的两倍。

默认情况下,每个进程使用的排序区不能超过1G。由参数_SMM_MAX_SIZE(单位KB)控制,默认为_PGA_MAX_SIZE(单位B)的一半。 例如,并行度20创建索引,总共可以使用的排序区大小为20*1G=20G,但是同时还受参数_SMM_PX_MAX_SIZE的控制,所有的slave占用的内存不能超过_SMM_PX_MAX_SIZE的值(单位为KB),默认为pga_aggregate_target的一半。同时64位系统下,每个进程可以使用的排序空间不能超过4G。所以即使把_SMM_MAX_SIZE调整大于4G也没有用。_SMM_PX_MAX_SIZE,所有并行查询的SLAVE进程能够用到的PGA总量。每个RAC 节点都可以用到这么多,限制的是本节点所有并行slave能够消耗的PGA

如何为
PGA_AGGREGATE_TARGET设置一个合理的值?

PGA_AGGREGATE_TARGET的设定经常是一个摸索的过程,这里给出官方的一个分配指导原则


PGA_AGGREGATE_TARGET =(TOTAL_MEM * 80%) * 20% for an OLTP system

PGA_AGGREGATE_TARGET = (TOTAL_MEM * 80%) * 50%for a DSS system

上面公式中的TOTAL_MEM * 80%代表着Oracle可以使用的所有内存为操作系统的80%,再根据不同类型业务的特点,OLTP系统,可以在此基础上分配20%的内存给PGADSS分析型系统,可以给出剩余内存的50%。这个只是一个指导的意见,具体情况要具体分析。例如,你的OLTP系统上有成千上万个连接,那么你可以粗略的按照每个进程占用10M的内存来大体的计算一下PGA需要占用的内存空间,再者,假如你的系统不但连接数非常多,而且活跃的连接数也非常的多,那么你可以按照每个进程至少12M的内存来进行估算,更为重要的,系统中假如存在非常多的临时性的计算任务,那么要为PGA预留的内存就更多了。 例如,并行度设置为5创建索引,每个并行进程占用的PGA内存接近1G


select *  from 
(select PGA_USED_MEM/1024/1024,PGA_ALLOC_MEM/1024/1024,PGA_MAX_MEM/1024/1024

from v$process order by 1 desc) whererownum<14;

PGA_USED_MEM/1024/1024  PGA_ALLOC_MEM/1024/1024  PGA_MAX_MEM/1024/1024

---------------------- --------------------------------------------
    
1043.70779          1044.39673        1044.39673

904.724821          905.334227        905.334227
851.350813          851.959227        851.959227
804.526175          805.146727        805.146727
589.681547          590.209227        637.584227
27.0686626          27.5379925        27.5379925
27.0686626          27.5379925        27.5379925

所以你在为系统规划PGA内存时不要忘了这些临时性任务需要占用的内存。他们可能是很大的一块哦。

该为数据库分配多少的PGA内存,除了把连接数的多少这个指标作为一个考量因素外,还需要关注活跃连接数的多少,这是因为很多系统连接数虽然非常的多,但是去数据库里一统计发现,绝大部分的连接已经几个小时甚至几天都没活跃过了,这往往是应用程序的连接池不加以管理的结果(也可能是其他原因)。对于不活跃的连接,Oracle每个进程的PGA占用不会太大,按照10M计算是个合理安全的值。AIX下可以大一些,按照每个15M-20M计算。

这里再提供一种估算每个空闲的服务器进程占用OS内存的方法。 首先通过操作系统命令free -m查看一下当前OS剩余的内存,69590M

echo 3 >/proc/sys/vm/drop_caches


#free -m
               total       used      free     shared    buffers    cach
ed

Mem:       128923      69590      59332          0          4        2
27

-/+ buffers/cache:      69358     59564
Swap:       15999       1276      14723


然后创建
2000个连接
test.sql
declare
L_N number;
begin
dbms_lock.sleep(600);
end;
/

#! /bin/sh
. /home/Oracle/.bash_profile
step=1
while [ $step -lt 2000 ]
do
nohup sqlplus test/test @test.sql &
let "step+=1"
echo $step
done


再次查看剩余的操作系统内存,通过没创建连接之前的剩余内存减去创建完
2000个连接之后的剩余内存可以估算出每个进程占用的内存大约为(59332-44548/ 2000=7M
free -m
                        total       used       free    shared    buffers     cach
ed

Mem:            128923      84374      44548          0         11        2
63

-/+ buffers/cache:      84099     44823
Swap:        15999       1276      14723


读者需要牢记,减少的
7M内存中,绝大部分都是进程本身占用的,只有1-2M的内存是PGA占用的。因此上面给大家推荐的值是10-12M,也就是给进程预留出一些PGA的内存来。

确认一个空闲进程占用的真正
PGA内存有多大,可以通过v$process视图中PGA_ALLOC_MEM字段来获得,如下:只有1.49M。但是就像上面已经提到的,这个进程从操作系统层面看却占用了7M左右的内存。

select round(PGA_ALLOC_MEM/1024/1024,2) from v$process where spid=5553;


ROUND(PGA_ALLOC_MEM/1024/1024,2)
--------------------------------
                
1.49


pga_aggregate_target
参数指定的值并不是一个硬限制,直到Oracle 12C才提供了一个参数来强制限制PGA的使用量。如果读者不知道该为自己系统的PGA设置一个什么样的值,可以通过视图v
 
sysmetric_history
selectbegin_time,end_time,value  
from v$sysmetric_history
where metric_name ='Total PGA Allocated';

BEGIN_TIME          END_TIME                 VALUE
-------------------   -------------------             ----------
2016-04-08 11:31:21 2016-04-08 11:32:21  323746816
2016-04-08 11:30:20 2016-04-08 11:31:21  323746816
2016-04-08 11:29:21 2016-04-08 11:30:20  328404992
2016-04-08 11:28:21 2016-04-08 11:29:21  323746816
2016-04-08 11:27:21 2016-04-08 11:28:21  323746816
2016-04-08 11:26:20 2016-04-08 11:27:21  323746816
2016-04-08 11:25:21 2016-04-08 11:26:20  323746816
2016-04-08 11:24:21 2016-04-08 11:25:21  326611968
2016-04-08 11:23:21 2016-04-08 11:24:21  323746816


上面查询的输出代表了各个时间段的,
PGA内存的使用量,结果集并没有完全列出来,读者可以根据PGA各个时间段的使用量来更加精准的去为自己系统的PGA如何做设定做决策。设定PGA的过程是一个循序渐进的过程。再次强调,一个进程占用的内存除了PGA之外,进程本身也会占用内存,这点上面我们已经讨论过。

按照
Oracle 2015OOW上的一份PPT提到,12C之前版本,PGA最多可用的内存可达到PGA_AGGREGATE_TARGET设定值的三倍,这里你听一下就行了,不必当真。

如果生产环境真的遭遇了
PGA严重使用过量的情况,可以通过Event 10261 来限制某个/所有进程PGA的使用,level后面值的单位为KB
alter session set events'10261 trace name context forever, level 100000';

一旦进程超出
PGA的设定配额,会被后台进程杀掉并报错,不同的版本可能报错的信息不一样:
·          For 11.2.0.4 and 12.1.0.1+, ORA-10260
·          For 11.1 - 11.2.0.3, ORA-600[723]

12C PGA_AGGREGATE_LIMIT

12C
之前的版本对于PGA的使用限制并没有一个硬限制,这个可能会导致一些问题,比如不加以限制后可能会导致OS SWAP的问题,一旦出现SWAP会导致Oracle性能的急剧下降,甚至导致DOWN机,我曾经遭遇过的一个案例是出现SWAP后,LGWR进程本身的内存出现了SWAP,数据库系统的表现是几乎完全HANG死,最后没办法只能重启解决问题。

对于这个新特性的使用是通过参数
PGA_AGGREGATE_LIMIT来限制PGA的使用上线,它是一个推导参数,在使用ASMM情况下,取以下的最大值
·           2GB
·         200% PGA_AGGREGATE_TARGET
·          3MB* PROCESSES

在使用
AMM情况下,肉丝还未找到PGA_AGGREGATE_LIMIT取值的规律,如果你知道,请告诉我哦。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页