《Oracle高并发系列1:DML引起的常见问题及优化思路》要点:
本文介绍了Oracle高并发系列1:DML引起的常见问题及优化思路,希望对您有用。如果有疑问,可以联系我们。
作者介绍
Oracle数据库是设计为一个高度共享的数据库,这里所说的“共享”,可以从数据库共享内存、后台进程、cursor、执行计划、latch等方面去理解.Oracle如此设计的目的是以最小的系统开销、最大化地支持更多的并发会话.也是基于这个设计思想,所以Oracle单个实例的垂直扩展能力一直是DB领域内的佼佼者.
之前曾经看到PG大牛的文章分析关于Oracle的CursorPin S为什么不会在PostgreSQL里面出现,其主要原因是PostgreSQL的执行计划不是全局共享的,而Oracle里面同样的Cursor在不同session间一般情况下都是可以共享的(Oracle在某些条件下会也触发重新硬解析).这样的设计客观来讲其实各有优劣,虽然PG的plan cache是不同会话不共享的,避免了高并发时不同会话对同一个cursor产生争用,但是也意味着同样的并发会话数的情况下,PG的会话所需求的cache会更多,而且每个会话都至少要parse一次;或者反过来说同样的资源限制的前提下,Oracle支持的并发数更高.
引用一位Oracle 7的OCP,资深Oracle老司机的一段话:“早期Oracle就是使用session私有内存,但当负载并发增加时,内存消耗成了问题,而且执行计划无法共享,增加率parse时间,对于OLTP系统parse时间的增加对于整体执行时间影响较大.因此Oracle基于这一点进行了优化,包括session cached cursor和shared pool等,减少了SQL执行过程中的parsing time和planning time.但没有免费的午餐,肯定会有其它消耗,类似内存结构的并发保护上的成本.总之:
这里不探讨哪个数据库更NB,每种数据库技术的发展会受多种因素的影响,包括商业战略、市场需求、软硬件技术成熟度等.我们采用Oracle多年,对于Oracle数据库有深厚的感情,但是目前也同时义无反顾地投入开源数据库和NoSQL的怀抱,技术无好坏,最适合应用场景的就是最好的.这里只重点探讨,当Oracle数据库的这些“共享”资源,遭遇高并发时的问题发生的原因和应对措施.
这里谈的是思路,不是具体的命令.
这里的处理方法,是基于过往发生过的实际案例总结而来.
Oracle的表是堆表,索引是B树,当对表做DML时,Oracle会对table的block进行操作,同时也对索引树的block进行维护,那么当同一时间有大量会话都需要对索引(或表)的同一个block做维护时,就会产生索引(或表)上面的争用.当出现争用时,v$session_wait显示了当前的会话正在等待的event name.
这个等待事件表明,当前的会话正在等待一个block上面的事务槽的分配,可能是table block或index block.
可能的原因有:
解决思路:
小知识点:
在v$lock中若看到某个会话正request一个lmode为4的锁,其原因之一就可能是ITL等待造成的,其它原因可能是并发操作主键、位图索引、分布式事务等.
这个问题一般发生在表在高并发insert操作时,等待在字段类型是日期、自增序列的索引block上.因为应用始终插入的都是最新(high key)的值,导致这些索引一般都是右倾斜增长的,也就是说最近最频繁的操作都发生在索引最右边的那个叶子块上,叶子块的free空间很快被填满,然后叶子块要分裂,分裂过程总要去找free block,index spliter的进程会持有一个enq:TX锁,其它并发insert的进程一般也正是需往最右边的这个index leaf block去insert数据,所以都要等待这个spliter进程完成并释放这个锁.(竞争更加激烈时,甚至会在branch block的split时产生)
解决思路:
2)event 43822启用后,对于root block的split进行了增强, 不会超过5次的index block reclamation,Oracle就会去申请分配新块了.
背景知识:
Oracle在索引split时中寻找可复用的free block的过程如下:
Oracle不会一开始就让index segment申请分配新的空间(这会造成index segment的空间过度增长) ,而是到该index segment的其它地方搜索是否存在可用的Free Block, 这些Free Block的要求是status是75%-100% Free的, server process会扫描这些75%-100% Free的block 并确认这些block 实际上是100%空的, 如果找到100% Free Block则使用;如果没有则继续搜索, 直到所有候选block都被检查过,这个行为叫做 probes on index block reclamation.每次寻找空块并failed ,oracle就会增加这个统计指标: “failed probes on index block reclamation”.Oracle内部机制会控制要找多少次,不会去FULL SCAN所有index block的,failed超过一定次数后就会申请分配新的block.
不能重用的原因有2个:
在这个过程中,Oracle还有机会找到的block其实已经是索引结构中的一个非空block,但是Oracle只会在splittingand relinking to index structure之后才会发现这个block其实是illegal的选择,这个时候Oracle会回滚这个操作,这个统计记录在‘transaction rollback’ in v$sysstat,然后继续寻找另外一个block.
Oracle进行找空块的过程中,如果这些块不在内存中,会增加物理读,如果这些块还需要做延迟块清除或者还要回滚,则需要触发更多系统递归操作,可见,如果“failed probes”过多,split效率低下时,会直接导致index contention增加.
TABLE的High WaterMark(即高水位线)标识table segment中已用空间和未用空间的边界,具体来讲,HWM以上的block的状态是:unformattedand have never been used; HWM以下的block的状态是:Allocated, but currentlyunformatted and unused、 Formatted and contain data、Formatted and empty because the data was deleted.当HWM以下的block都无空闲空间可以使用时,Oracle会推进HWM来申请分配新的block到segment里面,而HW enqueue锁被用来管理推进HWM分配新空间时的串行操作.
显而易见,当高并发的insert发生时,甚至表中若有LOB字段时情况更糟,HWM的推进分配新空间的速度赶不上并发会话所需空间的速度时,就会发生在HW的enq上的等待.
解决思路:
这个等待事件通常说明会话在等待Undo Segment,注意等待的原因一般其实并不是因为UNDO TABLESPACE没有空间了,UNDO表空间不足会直接报ORA-30036(NOSPACEERRCNT).
造成这个等待的典型场景有:
解决思路:
本文重要提示:
上述所有隐含参数的介绍,一方面是为了加深对Oracle相关管理机制的了解,另一方面都是在常规手段包括应用层调优的手段无法奏效的前提下的应急方案,在生产环境启用之前请得到Oracle原厂的确认与支持,而且在高峰期或问题应急解决后务必要取消隐参.
不要随意在生产环境使用隐含参数,这是一个最基本的数据库运维原则!
上面这些问题的解决思路其实都是治标不治本的,这些优化措施可能能够帮助你的系统度过当前的系统波峰,但是随着时间的推移当更大的波峰出现时,问题还会再次发生.优化“对数据库的需求”带来的效果永远大于优化“数据库所能提供的资源”,虽然有时候优化“对数据库的需求”的成本投入更高,但是投入与产出一般都是成正比的.从这个意义上来讲,若应用能够合理控制并发、系统架构中引入缓存层、采用异步队列处理机制、优化DB模型设计以及SQL写法等,这才是解决问题的根本之道.
文章出处:DBAplus社群
转载请注明本页网址:
http://www.vephp.com/jiaocheng/4410.html