资讯专栏INFORMATION COLUMN

oracle故障处理之cursor: mutex X分析

IT那活儿 / 3149人阅读
oracle故障处理之cursor: mutex X分析

最近一套12C库出现大量cursor:mutex X异常等待的故障,借此机会在这里和大家分享下分析过程及后续处理。先简单介绍下故障过程,一天数据库突然等待事件异常告警,登上数据库查看异常等待事件发现大量cursor:mutex X,基于优先恢复业务的原则,将其kill之后数据库恢复正常。后续开始对故障进行分析及进行后续处理,欲知详情,请听下面分解。


1、查看故障时段AWR:

发现cursor:mutex X异常等待事件占了54%的DBTIME


2、cursor:mutexx等待事件原理:

cursor正在被解析并尝试以独占(exclusive)模式获取cursormutex时产生的等待即为cursor:mutexx。


引起问题的原因包括频繁硬解析、highversioncount、cursor失效及未知BUG等。但本质上是一些会话长时间持有互斥锁,以至于其他会话不得不等待资源。如果在保护库缓存结构的latches/mutexes上发生争用,这意味着解析面临压力。解析SQL需要更长的时间,因为它无法获得所需的资源。这会延迟其他操作,并且通常会降低系统的速度。


查看问题刚出现时的历史会话(DBA_HIST_ACTIVE_SESS_HISTORY)如下:

从上图我们可以看到多个会话同时执行SQL_ID:3t5xt2hkrchpy,a9xqubd880h5n,且堵塞源不停在变,会话相互之间发生cursor:mutex X等待。


3、查看故障时段的AWR:

从以上图我们可以看到SQL_ID:3t5xt2hkrchpy执行时间及CPU消耗TOP1,其SQL及其他SQL的版本数都很高。


4、查看故障时段做的hang分析日志如下:



通过hang分析日志我们可以看到Blcoking其他session的会话操作是查找子Currsor,所以故障大概率是由于子Cursor过多,进行查找时发生等待导致。而产生大量的子Cursor的原因是NLSSettings。


普及下什么是versioncount?

一个SQL第一次执行时,会进行硬解析,同时创建parentcursor和childcursor。


当这个SQL时再次执行时,首先会对SQL语句进行特殊的hash运算,对应生成一个hashvalue。Hashvalue存放在parentcursor中,然后会用这个hashvalue到paranetcursor的bucket中匹配,如果相同的hashvalue 已存在parentcursor里,则继续遍历这个childcursor,如果可重用,那么就沿用childcursor的信息,如果不能重用,就会重新生成一个新的childcursor。一个parentcursor下childcursor的总数,就是这个SQL的versioncount。


highversion count指的就是childcursor总数很高。在AWR报告中,默认verioncount超过20的SQL就会显示在orderby version count中。根据经验versioncount如果超过100,可能就需要引起注意了。


5、综上所述,我们发现本次故障大概率是由于highversion count导致,那为啥这么多SQL的versioncount都这么高呢,初步怀疑是触发BUG了,我们这库是CDB模式,并且多个PDB的字符集不一致,通过MOS查找到一篇类似的文章:


通过SR确认有可能触发BUG25054064,该BUG在2020年1月份的DBRU中fixed了,我们只需要打上

Patch31741641: DATABASE OCT 2020 RELEASEUPDATE12.2.0.1.201020即可,因为DBRU都是累积的。

查看其readme提供的BUG修复的连接发现BUG25054064已在补丁集中。



6、打完补丁之后截止目前为止再没出现过类似的故障,我们查看SQL的versioncount发现降低了一个数量级。


另外由于字符集不匹配导致的highversion count在DocID 2542447.1也详细介绍了处理方法,用于缓解子Cursor过多查找缓慢导致的等待:


1)通过具体SQL_ID将其从sharedpool清除掉。

SQL>select address,hash_value,version_count from v$sqlarea wheresql_id=a9x5sbz88kmfh;

ADDRESSHASH_VALUE VERSION_COUNT
---------------- -----------------------
000000006BFFAC00 3498659280 2

SQL>exec dbms_shared_pool.purge(,C);
Ex:
SQL>exec dbms_shared_pool.purge(000000006BFFAC00,3498659280,C);

PL/SQLprocedure successfully completed.


2)将_cursor_obsolete_threshold参数设置为较低的值减少子Cursor数量,不过这个取决于应用程序需求,_cursor_obsolete_threshold的默认值是8192,可以将其设置为2048或1024,重启生效。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/130070.html

相关文章

  • 什么时候线程不安全?怎样做到线程安全?怎么扩展线程安全的类?

    摘要:什么时候会出现线程不安全操作并非原子。只有单个组件,且它是线程安全的。这种情况下,就是的线程安全实际是委托给了整个表现出了线程安全。 当多个线程去访问某个类时,如果类会表现出我们预期出现的行为,那么可以称这个类是线程安全的。 什么时候会出现线程不安全? 操作并非原子。多个线程执行某段代码,如果这段代码产生的结果受不同线程之间的执行时序影响,而产生非预期的结果,即发生了竞态条件,就会...

    wh469012917 评论0 收藏0

发表评论

0条评论

IT那活儿

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<