码迷,mamicode.com
首页 > 数据库 > 详细

Oracle Memory Management and HugePage (连载二)

时间:2016-04-22 20:14:25      阅读:245      评论:0      收藏:0      [点我收藏+]

标签:

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




MSMM

10GSGA的管理是通过手工设置一系列的参数来实现的,例如重要的参数有以下几个:

●             buffer_cache_size

●             shared_pool_size

●             large_pool_size

●             stream_pool_size

●             log_buffer

SGA是一大块内存的统称,由上面列出的组件组成,10G之前的版本,DBA需要对SGA的各个内存区域进行手工设置,这可能对一个DBA无形中要求变得非常的高,需要了解业务,了解热点数据量,了解SQL的使用方式,是否存在大量不同文本的SQL等等来决策来给每个区域分配多少内存。使用过这个版本的DBA基本都遭遇过一个经典的报错:ORA-04031,一般是由于shared pool内存不够导致,这个不够的原因可能有很多,共享池内存的严重碎片化,大量的硬解析,巨大的PL/SQL文本等等都可能会导致这个问题。下面我们来看下,手工管理SGA情况下,如何考虑为buffer cacheshared pool这两个最重要的内存组件分配内存。

Buffer Cache

Buffer Cache俗称数据块高速缓存,是用来缓存数据块的拷贝的,Oracle通过改进后的LRU算法以期待这些数据块后续被高效的重用。服务器进程从磁盘读入的数据就放在这块内存中,修改数据时,也是在这个区域对数据进行修改。并没有一个给buffer cache分配内存的黄金法则,还是要根据操作系统的内存大小,业务的热点数据量、业务的类型等因素来决定给buffer cache分配多大的内存大小。我们先看下如何决定整个SGA的大小,对于SGA的分配原则,官方建议如下:
技术分享

上面的公式格式跟PGA的公式大同小异,刨去20%内存给操作系统之后,分为了不同的系统类型,基本上是OLTP系统,大部分的内存给buffer cacheDSS类的系统,buffer cache没那么重要,可以给到50%甚至更低。 至于SGA中多少可以分配给buffer_cache,要看实际情况。DBA可以通过查看buffer cache的命中率来粗略了解是否给buffer cache分配了足够的内存。但是熟悉我的朋友都知道,我是OWI方法论的践行者,对于命中率的崇拜在Oracle里已然不应该再存在,但是命中率作为一种性能诊断的辅助手段依然具有它的价值。如果系统的SQL都足够优化后,命中率不高,一定程度上意味着可能buffer cache给小了或者你的业务访问的数据非常的离散,热点数量太少。这里肉丝给出的优化思路是自顶向下,命中率低是一个表象,最上层的应用是不是调用了大量不需要调用的SQL,这些SQL是不是缺少索引,SQL都足够优化后,DBA是不是考虑加大buffer cache来提升性能,加大之后还是不行,是不是要考虑增加系统内存来进一步提高buffer cache的大小,最后是不是需要为数据库多加几个盘或者使用SSD来提高性能。采用自顶向下的分析方法有利于真正发现问题所在而且以最低的代价解决问题,如果仅仅是一个SQL由于缺少索引而导致整个数据库系统缓慢,DBA直接就去加盘扩容IO,那么最终会发现花费了这么大的代价,治标不治本,问题依然没有解决。上面给出的公式并不适用于所有情况,特别是OLTP系统,如果进程数非常的多,那么需要进一步降低SGA占用内存的比例,以预留出更多内存给PGA使用。

Shared Pool

Oracle占用量最大的两块内存除了buffer cache区就是Shared Pool的内存了,它的结构非常的复杂,而且由于要缓存SQL代码这种非标准大小的文本,经常会产生大量的碎片化内存,shared pool总体上包含了两大部分,一块是library cache区,用来缓存SQLPL/SQL代码,保存它们的执行计划,提高SQL的解析效率,如果你的应用代码从来不使用绑定变量,那么这一块的内存对你来说是一个很大的负担,但是Oracle里是无法关闭library cache区的,因此对于OLTP系统,请确保SQL都使用了绑定变量。第二大块区域是row cache区,用来缓存数据库的数据字典,由于保存在里面的信息是以行的形式存在,因此叫row cache。对于这一块的内存,依据数据库中元信息(metadata)的多少而决定,如果数据库中有几十万的对象,那么这一块的内存就会占用比较大,同时表上的很多列都有直方图信息,也会导致这一区的内存占用比较大。在一个稳定的系统中,这一区域的内存基本上是静态的,Oracle中几乎没有操作会频繁修改row cache区。有个例外情况是没有cache属性的sequence,如果这种sequence调用频繁,就会触发频繁的修改sequence的属性值,进而可能会产生row cache lock的一些等待,优化的办法是为每一个sequence设置足够的cache值。 >如果应用程序没有使用绑定变量,而且难以修改,可以通过设置cursor_sharingforce来尝试解决问题。

这里肉丝再讲一个亲身经历的案例,老DBA嘛,可能技能已经不多,但故事还是有的????,曾经帮一位客户解决了一个free buffer waits的案例,这个等待事件的出现一般说明buffer cache过小,或者全表扫描、写入操作比较多、写脏数据比较慢,从AWR报告看,free buffer waits排在TOP EVENT的第一名,占用的DB TIME已达到了百分之七八十,而且从awr报告中发现客户的shared pool内存占用已经达到了接近50G,而分析数据库一个月之前的AWR报告,shared pool的内存只有3G左右的大小,基本上可以认定为shared pool内存占用过大,而导致buffer cache不够用,进而出现了free buffer waits等待事件,经过跟客户沟通后知道,以前一直比较稳定,最近做过的大的变更是给数据库使用了oracle flahcache,通过MOS上搜索flashcache关键字最终发现,在11.2.0.4Oracle RAC如果使用了flash cache,那么会在shared pool 中分配额外的内存存放GCS资源。多出的内存为:208 bytes * the total number of (flash) buffer blocks。因为这里提醒广大DBA朋友,如果你打算使用OracleFlashCache那么请为它预留出足够的shared pool内存。

ASMM


10G 版本Oracle推出了ASMM,自动SGA管理,它的出现一定程度上帮助DBA解决了管理SGA的问题,通过设置参数sga_target为非0值来启用ASMM。但是在10GR1,包括10GR2的早期版本,ASMM还不够成熟存在比较多的BUG,导致了比较多的问题,所以当时DBA在一些核心的生产环境,还是沿用了9I时候的手工SGA管理。自动SGA管理,不再需要为每个内存组件设定值,当然如果你设置sga_target的同时,设置了db_cache_size这些参数,那么db_cache_size这些参数值会作为最小值要求。

如果sga_target设置为0memory_target也为0,则回归到传统的MSMM管理。通过使用ASMM可以很大程度上解决上面提到的ORA-04031的错误。在使用了ASMM后,去查看spfile文件,会发现多了一些双下划线打头的内存参数如__db_cache_size,这些内存参数是Oracle实例运行过程中动态产生固化到spfile中的,如果实例运行的时间足够长,这些参数的值被固话后,相当于有了一个基于自身环境的最佳实践参数,数据库实例重启后,会沿用固化在spfile中的这些参数值。 > 11G版本即使sga_target设置为0memory_target也设置为0,也可能会发现SGApool之间Granule的移动,这是11G的新Linux特性,通过参数_memory_imm_mode_without_autosga来控制。 >

Granule

ASMM技术的实现,内部是通过Granule在内存组件之间移动来实现。这里对Granule做一点解释,Oracle 10G引入的自动共享内存管理,目的是为了解决下面的问题,我应该把db_cache_size设置为多大?我应该把shared_pool_size设置多大?那么10G以后,Oracle给出的答案是,你不用再考虑这个问题了,我通过算法帮你搞定。简单来说,就是通过比较通过增加数据块缓存减少的磁盘IO时间与通过增加共享池优化而节省的时间,通过比对,来得出是否需要在两者间来移动内存。为了让内存在db_cache_sizeshared_pool_size之间高效移动,Oracle9I版本中重新构建了SGA,也就是使用固定大小的内存块-GranuleGranule会随着操作系统、Oracle版本以及SGA大小的不同而不同,读者可以通过如下的SQL语句来查看当前实例的Granule的大小:


技术分享

AMM


有了PGA的自动管理,SGA的自动管理,Oracle 这个强迫症患者终于在11G这个版本推出了AMM,自动内存管理,由于使用了AMM后就不能使用大页,因此这个功能其实一直没被广泛使用,通过这个功能DBA只需要设置memory_target一个参数就可以完成整个数据库实例内存的配置,就像ASMM导致了一些双下划线隐含参数的产生,AMM同样导致了一些双下划线隐含参数的产生,例如:__pga_aggregate_target__sga_target。而且在11.2.0.2版本之前,DBCA建库默认就是AMM管理(有些时候Oracle胆子真的是很大),11.2.0.3以后开始DBCA建库时会检测操作系统内存大小,大于4G内存默认为ASMM,小于4G内存默认为AMM。同样如果你设置AMM后,也设置了SGA_TARGET等参数,那么这些参数会作为最小值要求。

AMM最大的问题是不能使用大页内存。关于使用大页的重要性会在本文后面部分详细介绍。 >Doc 749851.1 > > Doc 1453227.1.

11G后由于出现了AMM,如果你做DBA时间足够长,你一定遇到过下面这个错误


技术分享

这个错误给人莫名其妙的感觉,“MEMORY_TARGET特性不被支持,其实不是特性不被支持,这是由于AMM使用的是操作系统的共享内存文件系统,位于/dev/shm下,如果配置的内存文件系统比较小,小于了memory_target的值就会报错,一般在Linux主流的操作系统上,这个内存共享文件系统的值是内存大小的一半,如果读者遭遇了这个问题,要不去调小memory_target的参数值,要不通过如下办法去修改这个共享内存文件系统的大小:


技术分享

这里指出一点,11G ASM默认会使用AMM,官方强烈建议不要修改这个默认行为。ASM里要求MEMORY_TARGET的最小值为256M。如果设置了低于256M的值,Oracle会自动增加内存到256M。 对于ASM的发布版:11.2.0.3/11.2.0.4/12.1Oracle强烈建议把memory_target设置为1536M,这个值被证明在绝大部分的环境里都是足够的。

使用了ASM后,数据库实例的shared_pool内存需要重新评估计算,如下公式是在正常shared pool的基础上需要额外增加的大小:


技术分享

?             如果ASM磁盘组是external redundancy,需要在2MB基础上,每100G的空间,增加1MB

?             如果ASM磁盘组是normal redundancy,需要在4MB基础上,每50G的空间,增加1MB

?             如果ASM磁盘组是high redundancy,需要在6MB基础上,每33G的空间,增加1MB

ASM & Shared Pool (ORA-4031) (文档 ID 437924.1)


大页


对于类Linux系统,CPU必须把虚拟地址转换程物理内存地址才能真正访问内存。为了提高这个转换效率,CPU会缓存最近的虚拟内存地址和物理内存地址的映射关系,并保存在一个由CPU维护的映射表中,为了尽量提高内存的访问速度,需要在映射表中保存尽量多的映射关系。这个映射表在Linux中每个进程都要持有一份,如果映射表太大,就会大大降低CPUTLB命中率,主流的Linux操作系统,默认页的大小是4K,对于大内存来说,这会产生非常多的page table entries,上面已经提到,Linux下页表不是共享的,每个进程都有自己的页表,现在随便一个主机的内存都配置的是几十个G,几百个G,甚至上T,如果在上面跑Oracle不使用大页,基本上是找死,因为Oracle是多进程架构的,每一个连接都是一个独占的进程,大内存+多进程+不使用大页=灾难,肉丝在8年的DBA生涯里,至少帮助不下5个客户处理过由于没有使用大页而导致的系统故障,而这5个客户都是近三四年遇到的,为什么大页这个词提前个三五年并没有被频繁提起,而当下,大页这个词在各种技术大会,最佳实践中成为热门词汇?这是因为最近几年是Linux系统被大量普及应用的几年,也是大内存遍地开花的几年,而且现在一个数据库系统动不动就是几百上千个连接,这些都促成了大页被越来越多的被关注到。

大页的好处

我们来看一下使用了大页的好处:

●               少的page table entries,减少页表内存

●               pinSGA,没有page out

●               提高TLB命中率,减少内核cpu消耗

在没有使用大页的系统上,经常可能会发现几十上百G的页表,严重情况下,系统CPUsys部分的消耗非常大,这些都是没使用大页的情况下的一些症状。

大页的特点/缺点

●               要预先分配

●               不够灵活,甚至需要重启主机

●               如果分配过多,会造成浪费,不能被其他程序使用。

大页的分配方法

通过在文件/etc/sysctl.cnf中增加vm.nr_hugepages参数来为大页设定一个合理的值,值的单位为2MB。或者通过echo 一个值到/proc/sys/vm/nr_hugepages中也可以临时性的对大页进行设定。 至于应该为大页设定多大的值,这个要根据系统SGA的配置来定,一般建议大页的总占用量大于系统上所有SGA总和+2GB

HugePages on Oracle Linux 64-bit (文档 ID 361468.1),AIX页表共享,一般不用设置大页。

大页的原理


技术分享

以下的内容是基于32位的系统,4K的内存页大小做出的计算: 1)目录表,用来存放页表的位置,共包含1024个目录entry,每个目录entry指向一个页表位置,每个目录entry4b大小,目录表共4b*1024=4K大小 2)页表,用来存放物理地址页的起始地址,每个页表entry也是4b大小,每个页表共1024个页表entry,因此一个页表的大小也是4K,共1024个页表,因此页表的最大大小是1024*4K=4M大小 3)每个页表entry指向的是4K的物理内存页,因此页表一共可以指向的物理内存大小为:1024(页表数)*1024(每个页表的entry数)*4K(一个页表entry代表的页大小)=4G 4)操作系统将虚拟地址映射为物理地址时,将虚拟地址的31-2210位用于从目录表中索引到1024个页表中的一个,将虚拟地址的12-2110位用于从页表中索引到1024个页表entry中的一个。从这个页表entry中获得物理内存页的起始地址,然后将虚拟地址的0-12位用作4KB内存页中的偏移量,那么物理内存页起始地址加上偏移量就是进出所需要访问的物理内存地址。

由于32位操作系统不会出现4M的页表,因为一个进程不能使用到4GB的内存空间,有些空间被保留使用,比如用来做操作系统内核的内存。而且页表entry的创建出现在进程访问到一块内存的时候,而不是一开始就创建。

页表内存计算

32位系统下,一个进程访问1GB的内存,会产生1M的页表,如果是在64位系统,将会增大到2M。 很容易推算,如果一个SGA设置为60G,有1500Oracle用户进程,64Linux的系统上,最大的页表占用内存为:60*2*1500/1024=175G,是的,你没看错,是175G!但是实际情况看到的页表占用可能没有这么大,打个百分之四五十的折扣,这是因为只有服务器进程访问到SGA的特定区域后,进程才需要把这一块对应的页表项加入到自己的页表中。

11.2.0.3版本

11.2.0.3版本之前,如果分配的大页数量不足,那么Oracle启动过程中不会使用大页,转而使用小页,但是在11.2.0.3版本后,Oracle在启动时同样会尝试使用大页,如果大页的数量不够,那么会把当前配置的大页使用完,不够的部分再从小页中去获取,这一行为实际上是通过Oracle的一个参数来控制USE_LARGE_PAGES,后面会对这个参数做详细解释。通过数据库实例的alert文件可以清楚的看到这一情况的发生:


技术分享
技术分享

Total Shared Global Region in Large Pages = 1024 MB (85%),代表只有85%SGA被放在了大页中。RECOMMENDATION部分,建议你至少增加89个大页来让SGA完全放到大页中。

USE_LARGE_PAGES

这个参数用来控制数据库实例启动时,对于大页内存的使用行为。有3个值在11.2.0.3版本之前,11.2.0.3版本多了一个值auto

?             true 默认值,尽可能使用大页,有可能有一些页在大页中,有一些在小页中,这种情况下通过操作系统命令ipcs -ma可能会看到内存分段(内存分段可能有多重情况都会导致,例如开启numa也可能会导致内存分段)

?             false 不使用大页

?             only 选项代表强制使用大页,否则无法启动

?             auto 11.2.0.3)在实例启动时,通过后台进程dism echo xxx > /proc/sys/vm/nr_hugepages 来尽可能的使用大页

以下代码为在参数设置为auto情况下alert的输出:


技术分享

可以看到启动实例过程中,优先启动了DISM进程,通过这个进程来自动完成大页的配置。$Oracle_HOME/bin/oradism的权限也是root权限,因为如果是grid权限不能完成大页的配置echo xxx > /proc/sys/vm/nr_hugepages

Transparent Hugepage

RedHat6, RedHat7, OL6, OL7 SLES11  UEK2 kernels开始transparent hugepage被默认开启,它允许大页做动态的分配,而不是系统启动后就分配好,根据Oracle MOS DOC1557478.1transparent hugepage导致了很多的问题,建议将其关闭 查看是否启用了transparent hugepage cat /sys/kernel/mm/transparent_hugepage/enabled [always] never []内的值是当前启用的值,上面的输出说明启用了transparent hugepage 可以通过 /etc/grub.conf 文件来关闭transparent hugepage


技术分享

通过增加关键字transparent_hugepage=never来讲transparent hugepage关闭。 也可以通过开机启动后,echo相应的值到对应的文件来动态关闭transparent hugepage


技术分享

OS层面查看大页使用情况


技术分享

HugePages_Total为所分配的页面数目,和Hugepagesize相乘后得到所分配的内存大小。43000*2/1024大约为84GB

HugePages_Free为从来没有被使用过的Hugepages数目。即使Oracle sga已经分配了这部分内存,但是如果没有实际写入,那么看到的还是Free的。这是很容易误解的地方。

HugePages_Rsvd为已经被分配预留但是还没有使用的page数目。在Oracle刚刚启动时,大部分内存应该都是Reserved并且Free的,随着Oracle SGA的使用,ReservedFree都会不断的降低。

HugePages_Free – HugePages_Rsvd 这部分是没有被使用到的内存,如果没有其他的Oracle instance,这部分内存也许永远都不会被使用到,也就是被浪费了。在该系统上有11.5GB的内存被浪费了。

最佳实践

对于Oracle来说,这是一个最佳实践泛滥的时代,所有的最佳实践其实都有特定的应用场景,而不是放之四海皆准,但是当今信息爆炸时代(数据库种类爆炸时代),很多DBA没有那么多的耐心去专注学习一门数据库,只是拿来主义从网上找出一些最佳实践来,不管三七二十一就用到自己的环境中(甚至是生产环境中),一定程度上来说,崇拜最佳实践是懒惰的结果。

针对于Oracle的内存分配方式,肉丝给大家推荐在核心系统上: 1.使用手工的SGA管理,这种管理方式已经非常的成熟,但是这种方式对DBA要求较高,一定程度上需要了解业务特点。 2.如果第一种方法你感觉到比较难,那么使用ASMM,但是为buffer cache,shared pool设定最小值的方式,这种方式是我非常推荐的方式。

至于AMM这种内存分配方式,由于不能使用大页,建议不要去用。

具体到内存如何分配,针对是OLTP场景,还是OLAP场景,有着不同的内存分配原则,即使是OLTP场景,针对进程数的多少,并发数的多少,SQL语句的特点,都会导致产生不同的内存分配方法。作为DBA要掌握基本的Oracle内存使用原理,然后根据实际情况去根据业务自身特点分配内存。

不管是OLTP系统或者OLAP系统,一般都建议至少为操作系统预留出20%的内存空间,这些内存空间用于kernalpage table以及一些其他的进程需要,例如rman备份,文件系统缓存。这个也是Oracle官方的建议。

把这一部分的内存刨去后,针对OLTP系统,可以考虑先尝试预留出20%的内存给PGA使用,80%的内存给SGA使用。如果系统上进程数比较多,特别是同时活跃的进程数比较多,需要给PGA预留出更多的内存,可以按照每个进程12MPGA占用进行计算。

针对OLAP系统,刨去操作系统的预留内存后,可以考虑预留出50%的内存给PGA使用,50%的内存给SGA使用。毕竟在纯OLAP下,buffer cache其实不需要那么大的内存空间。
技术分享

SGAPGA分配好后,要考虑到是否需要为buffer cacheshared pool来手工设定一个值,就像上文已经提到过的,可以参考buffer cache 的命中率,Library Hit的命中率作为一个辅助参考.如果命中率较低,有可能是内存分配的不够合理。当然你还需要借助于像AWR报告这样的工具,根据SQL的执行计划等内容来进一步的做诊断,比如命中率低的原因可能不是分配的buffer cache小,而是存在大量的低效的全表扫描,进而导致命中率低,这样的话,需要优化的就是SQL,而不是继续加大buffer cache。再比如,如果你发现Library cache Hit比较低,可能并不是shared pool比较小,还可能是系统的SQL存在大量未使用绑定变量的情况,导致硬解析过重。

优化经常是个系统工程,不能一蹴而就,特别像Oracle是一个很庞大的复杂系统,对于问题的出现,更是要仔细推敲,不能轻易的下结论。随着做DBA时间越来越长,你也会越来越懂TOM的一句话:It depends

关于作者

魏兴华,沃趣科技高级技术专家,主要参与公司一体机产品、监控产品、容灾产品、DBaaS平台的研发和设计。曾就职于东软集团,阿里巴巴集团,Oracle ACE组成员,DBGEEK 用户组发起人,ITPUB认证博客专家,ACOUGSHOUG核心成员。曾在Oracle技术嘉年华、ORCL-CONYY分享平台等公开场合 多次做过数据库技术专题分享。对Oracle 并行机制、数据库异常恢复方法、ASM等有深入的研究,人称”Oracle Internal达人,对企业数据库架构设计、故障恢复、高并发下数据库性能调优有丰富的经验,擅长从等待时间角度分析解决数据库性能问题,是OWI方法论的提倡者和践行者。

个人邮箱: xinghua.wei@woqutech.com

DB GEEK QQ :516293316

公司主页:www.woqutech.com

其它白皮书

SQL MONITOR: http://pan.baidu.com/s/1gfO2DtL

Parallel原理实现: http://pan.baidu.com/s/1i5xun9F

12C IN-MEMORY http://pan.baidu.com/s/1ge7r1oZ

(全文完结


Oracle Memory Management and HugePage (连载二)

标签:

原文地址:http://blog.csdn.net/woqutechteam/article/details/51202453

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!