Oracle Memory Management and HugePage (连载一)

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




概述

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

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


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

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

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

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


Memory
构成

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

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

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

PGA 自动管理

Oracle 是多进程的架构,这点区别于 MYSQL MYSQL 是单进程多线程的架构, 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 内存的杀手,每一个并行进程都能使用到最多 2G PGA 内存,当然 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 不能超过 2 G ,通过修改隐含参数可以突破这个限制。 > 肉丝在这里警戒各位,这些参数如果要在生产环境使用,请在你的数据库版本下做好测试。
以下为 11GR2 版本的情况,其他版本并未做测试:
·          _PGA_MAX_SIZE 每个进程的 PGA 的最大内存大小。默认值为: 2147483648 2 G ,单位为 B
·          _SMM_MAX_SIZE 每个进程的工作区的大小,默认值为 1/2 _PGA_MAX_SIZE 1048576 ,单位 KB 1GB ,排序区、 hash 区都属于工作区的范围。 64 位系统下真实使用的排序区内存不能超过 4GB
·         _SMM_PX_MAX_SIZE 所有并行查询的 SLAVE 进程能够用到的 PGA 总量。默认值为 1/2 pga_aggregate_target ,单位为 KB RAC 环境下,每个节点都可以用到这么多内存。

以上全部为动态参数,可以在 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 位系统下,每个进程可以使用的排序空间不能超过 4 G 。所以即使把 _SMM_MAX_SIZE 调整大于 4 G 也没有用。 _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 2015 OOW 上的一份 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 取值的规律,如果你知道,请告诉我哦。



来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28218939/viewspace-2081645/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/28218939/viewspace-2081645/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值