几个礼拜前, 有一套10.2.0.2 的 二节点RAC 数据库因为增大db_cache_size , 引发其中一个实例发生著名的ORA-04031 错误,日志如下:
Errors in file /oracle/oracle/admin/maclean/udump/u1_ora_13757.trc: ORA-00603: ORACLE server session terminated by fatal error ORA-00604: error occurred at recursive SQL level 1 ORA-04031: unable to allocate 1048 bytes of shared memory ("shared pool","select name,online$,contents...","Typecheck","kgghteInit") ORA-00604: error occurred at recursive SQL level 1 ORA-04031: unable to allocate 1048 bytes of shared memory ("shared pool","select name,online$,contents...","Typecheck","seg:kggfaAllocSeg") Thu Oct 13 08:25:05 2011 Log from www.askmac.cn & www.askmac.cn Errors in file /oracle/oracle/admin/maclean/udump/u1_ora_1444.trc: ORA-00603: ORACLE server session terminated by fatal error ORA-00604: error occurred at recursive SQL level 1 ORA-04031: unable to allocate 4120 bytes of shared memory ("shared pool","select name,online$,contents...","Typecheck","kgghtInit") ORA-00604: error occurred at recursive SQL level 1 ORA-04031: unable to allocate 4120 bytes of shared memory ("shared pool","select name,online$,contents...","Typecheck","kgghtInit")
以上错误出现的同时实例出现大量的row cache lock字典缓存和cursor:pin S wait on X等待事件,说明共享池中的row cache字典缓存和SQL area 执行计划因为Free Memory不足而被不断换出,导致硬解析增多并SQL解析性能下降,进一步造成了应用程序挂起,赶到现场后对该ORA-04031错误进行了分析。
SGA中的内存池包含不同大小的内存块。当数据库启动时,会有一块大的内存被分配并使用Free list的空闲列表追踪。随着时间推移,这些内存被不断分配和释放,内存块(chunk)被按照其大小在不同的Fress list中移动,当SGA里任何一个内存池出现不能满足内部分配一整块连续的内存块请求时,就可能出现ORA-04031错误。实际使用中造成ORA-04031错误的原因可能是Oracle软件bug、产品缺陷、应用程序设计不当、Oracle内存参数设置不当。
这里出现ORA-04031错误的内存池是shared pool即共享池,为了搞清楚ORA-04031错误发生的实际原因,我们通过AWR报告分析共享池的使用情况。
以下是 ORA-04031 问题发生前一天AWR报告中的共享池内存使用情况:
Pool | Name | Begin MB | End MB | % Diff |
---|---|---|---|---|
large | free memory | 112.00 | 112.00 | 0.00 |
shared | ASH buffers | 25.60 | 25.60 | 0.00 |
shared | CCursor | 19.44 | 20.16 | 3.70 |
shared | Checkpoint queue | 5.87 | 5.87 | 0.00 |
shared | PCursor | 10.57 | 11.14 | 5.38 |
shared | event statistics per sess | 7.72 | 7.72 | 0.00 |
shared | free memory | 32.99 | 33.00 | 0.02 |
shared | gcs resources | 78.75 | 78.75 | 0.00 |
shared | gcs shadows | 49.61 | 49.61 | 0.00 |
shared | ges big msg buffers | 15.03 | 15.03 | 0.00 |
shared | ges reserved msg buffers | 7.86 | 7.86 | 0.00 |
shared | ges resource | 5.28 | 5.28 | 0.00 |
shared | kglsim heap | 16.63 | 16.63 | 0.00 |
shared | kglsim object batch | 25.63 | 25.63 | 0.00 |
shared | library cache | 21.32 | 22.01 | 3.23 |
shared | row cache | 7.13 | 7.13 | 0.00 |
shared | sql area | 64.06 | 61.55 | -3.91 |
streams | free memory | 64.00 | 64.00 | 0.00 |
buffer_cache | 3,936.00 | 3,936.00 | 0.00 | |
fixed_sga | 2.08 | 2.08 | 0.00 | |
log_buffer | 3.09 | 3.09 | 0.00 |
以下是 ORA-04031 问题发生时AWR报告中的共享池内存使用情况:
Pool | Name | Begin MB | End MB | % Diff |
---|---|---|---|---|
large | free memory | 112.00 | 112.00 | 0.00 |
shared | ASH buffers | 25.60 | 25.60 | 0.00 |
shared | Checkpoint queue | 5.87 | 5.87 | 0.00 |
shared | KCL name table | 9.00 | 9.00 | 0.00 |
shared | event statistics per sess | 7.72 | 7.72 | 0.00 |
shared | free memory | 25.56 | 25.52 | -0.12 |
shared | gcs resources | 143.39 | 143.39 | 0.00 |
shared | gcs shadows | 90.33 | 90.33 | 0.00 |
shared | ges big msg buffers | 15.03 | 15.03 | 0.00 |
shared | ges reserved msg buffers | 7.86 | 7.86 | 0.00 |
shared | library cache | 7.59 | 7.65 | 0.80 |
shared | row cache | 7.13 | 7.13 | 0.00 |
shared | sql area | 8.70 | 7.35 | -15.57 |
streams | free memory | 64.00 | 64.00 | 0.00 |
buffer_cache | 7,168.00 | 7,168.00 | 0.00 | |
fixed_sga | 2.09 | 2.09 | 0.00 | |
log_buffer | 3.09 | 3.09 | 0.00 |
红色部分标注了2个报告中差异最大的地方,在问题发生时共享池中gcs resources和gcs shadows 2种资源对比前一天增长了169M。 gcs资源在共享池中享有较高的优先级, 而普通的SQL语句或执行计划享有较低的优先级,因为gcs资源所占用空间的大量膨胀,导致在没有调大共享池大小的情况下sql area和row cache内存资源被换出进而引发SQL解析性能下降和ORA-04031问题。
gcs resources和gcs shadow资源均是Oracle RAC中特有的全局缓存服务资源,这些资源负责处理RAC中的全局buffer cache。 同时这些资源所占用共享池的空间视乎Oracle实例所使用高速缓存的大小而决定,Metalink文档说明了该问题:
“The ‘gcs resources’ and ‘gcs shadows’ structures are used for handling buffer caches in RAC, so their memory usages are depending on buffer cache size. We can use V$RESOURCE_LIMIT to monitor them.”
当实例高速缓存buffer cache被大小时gcs资源所占用的空间也相应增长,具体算法如下:
‘gcs_resources’ = initial_allocation * 120 bytes = “_gcs_resources parameter” * 120 bytes ‘gcs_shadows’ = initial_allocation * 72 bytes = “_gcs_shadow_locks parameter” * 72 bytes select * from v$resource_limit where resource_name like '%gcs%'; RESOURCE_NAME CURRENT_UTILIZATION MAX_UTILIZATION INITIAL_ALLOCATION LIMIT_VALUE ------------------------------ ------------------- --------------- --- gcs_resources 507772 514607 976083 976083 gcs_shadows 133862 139927 976083 976083
我们可以通过现有的v$resource_limit视图中的INITIAL_ALLOCATION估算Buffer cache增加后的INITIAL_ALLOCATION数量,例如我们准备将db_cache_size从10g增加到20g,那么可以通过下列公式算出有必要增加的共享池大小:
add_to_shared_pool_size= 140 * Buffer_cache增加的兆数 * 192 bytes * 1.6
= 140 * 10* 1024 * 192 * 1.6 = 440401920 = 420M
问题总结
由于RAC环境中Oracle 使用共享池中的gcs resource/shadow 资源管理 全局缓存 , 当实例的Buffer Cache总量增加时gcs resource/shadow 这些资源的数目也会相应上升 , 这导致共享池中可用的剩余空间大幅下降,又因为 gcs 全局缓存资源在共享池中享有较高的优先级( perm ,且在10.2中 gcs资源不能和其他如row cache或library cache 共享一个Extent的内存区间) , 引发了大量的row/dictionary cache字典缓存和SQL执行计划被换出共享池, 引发大量的解析等待: cursor pin s on x 和 row cache lock , 最终还是 没有避免ORA-04031 的错误被触发。 这里要补充一句, 因为这套10g 的系统没有 启用ASMM(Automatic Shared Memory Management) 特性 且 共享池本身设置地较小(shared_pool_size=512MB) , 都是导致该ORA-04031 错误较为显性地被触发的因素 。
在<深入了解ASMM>中我介绍了ASMM的一些优点, 这里再罗列一下:
手动管理SGA的缺点在于:
- 个别组件如shared pool、default buffer pool的大小存在最优值,但组件之间无法交换内存
- 在9i中就提供了多种内存建议(advisor),但都要求人工手动干预
- 无法适应工作负载存在变化的环境
- 往往会导致内存浪费,没有用到实处
- 若设置不当,引发著名的ORA-04031错误的可能性大大提高
ASMM自动管理SGA的优势在于:
- 全自动的共享内存管理
- 无需再配置每一个内存组件大小参数
- 仅使用一个参数sga_target驱动
- 有效利用所有可用的内存,极大程度上减少内存浪费
- 对比MSMM其内存管理模式:
- 更加动态
- 更加灵活
- 并具备适应性
- 易于使用
- 一定程度上增强了性能,因为内存分配更为合理了
- 当某个组件急需更多内存时可以有效提供,因此可以一定程度避免ORA-04031的发生
解决方案
可以通过以下2种方式避免该RAC环境中特有的由增大Buffer_Cache导致GCS资源空间膨胀造成的ORA-04031问题:
- 在增加Buffer_Cache的同时估算所需相应增长的shared pool共享池大小
- 使用10g的SGA自动管理内存ASMM方式可以一定程度上避免ORA-04031错误的发生,但是自动管理方式存在实际使用时存在一些缺点,建议在启用ASMM:SGA_Target的同时,设置 shared_pool_size和 db_cache_size的最小大小,以最大可能避免因resize造成的问题; 同时建议设置_enabled_shared_pool_duration=false,禁用shared pool duration特性,也可以一定程度上减少ORA-04031发生的概率。
_enabled_shared_pool_duration:该参数控制是否启用10g中特有的shared pool duration特性,当我们设置sga_target为0时该参数为false;同时在10.2.0.5前若cursor_space_for_time设置为true时该参数也为false,不过在10.2.0.5以后cursor_space_for_time参数被废弃