Recent Posts

RSS Feeds

谈谈内存分配

这篇文章是我04年写的,现在修改一下发到博客上。

经常有人问我:"我们的系统有XX内存,怎么分配内存合适?"

我的回答是"不知道"。这是一个很无奈的答案,因为这个问题确实无解。每个系统都有不同的特性,如果使用一种通用的模式去分配内存,那么肯定是无法达到目的的。优化内存配置的时候,首先需要注意一些原则性的问题,更为准确的内存分配方法,需要根据科学的评估才能做出。以下几点是笔者在实际工作中总结的内存优化的基本原则:

第一,无论如何分配内存,绝对不能让系统存在较多的换页情况,最好的选择是让系统基本不存在换页。并且随时保留足够的空闲物理内存,以应对突发的业务高峰。宁可让你的DB CACHE命中率较低,也不要为了提高DB CACHE的命中率而过多的使用物理内存,导致物理内存换页。

第二,使用文件系统并不能给ORACLE数据库的IO性能带来好处,因此尽量使用裸设备,如果使用裸设备,SGAPGA使用内存的总量可以高达70%,甚至更高,但是SGAPGAOracle后台进程、Oracle前台进程、应用进程占用内存的总量一般不要超过系统物理内存总量的90%。上述的参考值仅仅提供参考,不能机械地说SGAPGA不能占用超过物理内存的60%或者70%,而是要根据你的系统的实际情况进行调整。如果你的系统有很大的物理内存,那么这些指标值还可以更高,只要遵循系统不产生换页操作的原则,那么哪怕你使用了95%甚至更多的物理内存,那么你的配置也是合理的。在海量内存下,如果配置了很大的SGA,那么会消耗大量的CPU资源,因此如果数据库实际不需要使用那么多内存,配置过大的SGA会导致CPU资源的浪费。因此调整SGA的同时要考虑CPU的情况,如果CPU已经出现了瓶颈,加大SGA可能会带来更大的CPU压力。切忌在解决内存问题的同时带来新的性能故障。

第三,在内存允许的情况下,设置足够大的PGA空间,尽量避免硬盘排序。硬盘排序会造成IO压力增大和相应速度大幅度下降,因此在有条件的情况下,提高内存排序比例可以提高系统的性能。如果排序操作很大,而且物理内存也有限,那么产生部分硬盘排序也是正常的。但是如果系统中存在大量的multi-pass的硬盘排序,那么就应该加大PGA空间了。

第四,在一般情况下,共享池和各个数据块缓冲池的命中率尽量保持在95%以上(OLAP应用除外)。由于每个应用都有不同的特点,命中率指标不一定能够完全表现出数据缓冲池的实际情况,但是在大多数情况下,这个命中率具有一定的代表性。如果在使用多缓冲的情况下,总体的命中率指标超过95%不能证明数据库缓冲池没有问题。通过检查DEFAULTKEEPNK CACHE等的命中率情况,往往能够发现在整体命中率达标的情况下,个别缓冲区性能不佳的问题。

第五、在 Oracle 9i 之前,过大的 shared pool 会导致大量的管理开销,因此不能设置过大的 shared pool(这一点其实也不是绝对的,如果CPU足够强劲的话,一个超过4G的共享池并不一定就会带来性能问题) 。 Oracle 9i 改进了共享池的管理,并且采用了 subpool 机制,使大型共享池的性能得到了很大的改善。笔者曾经在 9i 数据库上使用过超过 5G 的共享池,没有发现由于共享池过大导致�性能问题。在一些移动公司的大型BOSS系统中,超过8GB的共享池也是十分常见的,我曾经见过一个有300G内存的系统,共享池配置了10GB。另外要注意的是,如果已经使用了很大的共享池,还是出现共享池不足的问题,那么调整应用比加大共享池更为有效,另外如果由于某种原因,共享池存在碎片问题,SUBPOOL可能成为一种负面的东西,这个时候禁止使用SUBPOOL会带来好的效果。如果存在较为严重的共享池碎片,那么PX MSG POOL可能会导致经常出现共享池无法分配的情况出现,这种情况下,将PX MSG POOL在LARGE POOL中分配,可以减轻共享池不足的现象,另外减少SESSION_CACHED_CURSORS也会起到好的效果。在一般情况下,过大的共享池是不正常的。过大的共享池也会带来加大 CPU 开销等问题,因此在适当的情况下加大共享池的大小,而不要片面调大共享池,在有些情况下,将 SQL 和 PL/SQL 对象 PIN 到共享池中可能比扩大共享池具有更好的效果。

第六、LOG BUFFER是一个环状的BUFFER,用于将SERVER进程中的REDO LOG信息写入REDO LOG BUFFER中,以便于LGWR将BUFFER的数据写入REDO LOG文件。对于log buffer的设置,过大的log buffer不能改善REDO LOG的性能。一般来说LOG BUFFER的大小在几百K到几兆之间。Oracle 9i的安装指南建议LOG BUFFER的大小是128K*CPU的数量。对于REDO LOG产生量特别大的系统,可以使用这个建议值的数倍。对于一些类似电信计费账务系统的REDO 产生量很大的系统,设置超过10M甚至30M的LOG BUFFER,可能对REDO的性能有帮助。判断LOG BUFFER是否存在性能问题,闩锁REDO SPACE ALLOCATION会存在一定的争用,另外统计值redo log space requests也会出现异常。对于LOG_BUFFER,还有一个最为常见的误区就是超过3M的LOG BUFFER是没有意义的。这个错误的论断出自于LOG BUFFER刷入LOG FILE的规则,其中一个是LOG BUFFER的数据超过1M,就会触发LGWR写,另外就是LOG BUFFER超过1/3就会触发LGWR写。这里就很容易产生一个错误的论断,就是反正超过1M的LOG BUFFER数据就会触发LGWR写,那么超过3M的LOG BUFFER就没有意义了。这个论断忽视了一个问题,就是LOG BUFFER是环状的,在LGWR想LOG FILE中写入数据的时候,LOG BUFFER的尾部还是可以写入REDO 数据的,因此大的LOG BUFFER在某些场合还是有意义的。


第七、一般来说,多数据缓冲池的使用会对系统的性能提高有益。由于缓冲池采用HASH链的方式进行管理,因此对于数据缓冲池很大的系统,管理单个大型缓冲池的开销要远大于管理多个较小缓冲池的开销。使用KEEP池、RECYCLE池以及NK缓冲池可以分散数据的分布,减少由于各种竞争带来的缓冲池的额外开销。

第八、通过工作缓冲(通过*_area_size参数设置)来减少SQL执行过程中使用临时表空间,可以提高SQL的响应速度,减少系统IO。如果是Oracle 9i以前的版本,通过设置合理的工作缓冲区参数,可以实现上述目标。在Oracle 9i以后的版本,可以通过PGA自动管理来管理这些缓冲区, PGA自动管理可以大大提高各种工作缓冲区的使用率,在最小程度占用系统物理内存的情况下,提高各类工作缓冲区的使用率。

第九、LARGE POOL是和SHARED POOL类似的缓冲池,不过只有特定的BUFFER才会在LARGE POOL里分配。第一种情况,在SHARED SERVER模式(旧版本称为MTS)下,UGA空间是从LARGE POOL中分配的;第二种情况,作为顺序文件IO的缓冲区,最典型的就是RMAN备份的时候分配LARGE POOL作为缓冲区,另外从ORACLE 8I开始,如果PARALLEL_AUTOMATIC_TUNING设置为TRUE,那么并行操作的缓冲区也从LARGE POOL里分配。如果没有使用SHARED SERVER,那么系统对LARGE POOL的使用量是很小的,保持50-80M的LARGE POOL就足够了

第十、JAVA POOL是另外一个缓冲池,主要是为ORACLE JVM提供缓冲。如果应用软件很少使用JAVA的存储过程等,那么JAVA POOL不需要设置很大。

第十一、过大的数据块缓冲会导致大量的BUFFER GET扫描,增加CPU的开销。同时维护大量的缓冲池也会带来额外的CPU开销。同样,过大的共享池会导致共享池管理开销的增大。因此片面追求提高命中率的做法是不足取的。按需分配各种缓冲区的大小,不要过度分配缓冲区是一个十分重要的原则。

第十二、9i以后支持的SGA动态调整技术可以为缓冲区动态调整提供了技术手段。DBA可以根据实际情况,随时对SGA的各种缓冲进行调整。

第十三、Oracle 10G提供了自动共享内存管理(ASMM),ASMM机制可以根据系统的状态自动调整共享内存的大小。如果系统不是很大,内存资源比较充分,而且DBA的管理水平不足的话,使用ASMM可以免除DBA这方面的维护工作,使系统保持在一个较好的运行水平上。如果系统种存在性能瓶颈,而且系统的内存资源存在竞争,那么就要慎用ASMM。

Permalink     No Comments



发表一条评论:
  • HTML语法: 启用