暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

一个由死锁引起的系统HANG死问题分析

白鳝的洞穴 2020-06-11
3397
某用户的系统经常会出现下面的报错信息,同时数据库被HANG住,无法进行任何操作(包括登录),通过操作系统监控,发现总的CPU使用率并不高,但是会有1-2个CPU的使用率超过90%,甚至接近或达到100%。其他的CPU都很空闲。

Errors in file/oracle/app1/oracle/product/9.2/admin/bsssz/udump/bsssz_ora_10892.trc:

ORA-00600: 内部错误代码,参数: [kksscl-inf-inl-loop],[2500], [592], [603], [1211], [1211], [], []

Tue Apr 18 13:48:25 2006

Errors in file/oracle/app1/oracle/product/9.2/admin/bsssz/udump/bsssz_ora_8253.trc:

ORA-00600: 内部错误代码,参数: [kksscl-inf-inl-loop],[2500], [424], [454], [909], [909], [], []

通过TOP命令观察,有1-2个数据库SERVER进程十分繁忙。如果KILL繁忙的数据库进程,系统就会恢复正常。有时候,不KILL进程,系统几十秒到几分钟后系统会自动恢复正常。ORACLE的技术支持人员也到现场进行了处理。根据现场观察,认为是BUG2235386。并且已经打了2235386补丁。打补丁后,仍然出现了相同的故障,说明补丁2235386并不能彻底解决本故障。从这个ORA-600错误的主要原因是共享池闩锁争用,等待某个LIBRARY CACHE对象的闩锁产生了INTERNAL DEADLOCK。

接到客户发来的TRACE后我们又仔细分析了ALERT LOG,发现了一个有趣的现象,就是在这个ORA-600的前后都会出现一个或者几个ORA-60错误:


有的相隔几分钟,有的甚至相隔十多分钟,所以这个现象也没有引起大家的注意。于是我让用户观察一下下次出现类似问题时,CPU使用率很高的那个进程是不是就是产生死锁的进程。因为这个问题出现的很频繁,每隔几天就会出现一次,有时候一天都会出现几次,最短的几十秒,最长的十几分钟。于是很快用户就确认了,确实出问题的时候,伴随着死锁发生,而且那个CPU使用率较高的进程就是死锁产生的进程。

同时通过对产生ORA-600的会话进行分析,发现了以下几个特点:

1、通过对ORA-600[KKSSCL-INF-IN1-LOOP]进行分析,发现报错的SESSION正在等待某个子CURSOR分析完成。等待的CURSOR都有或多或少的子CURSOR,多的有200300个子CURSOR,少的有510个子CURSOR;

2、等待子CURSOR编译完成的CURSORSQL语句没有任何规律

3、死锁的SESSIONSQL语句一般是UPDATEDELETE语句。都包含或多或少的子CURSOR(几个到几百个)

4、为了了解在故障发生时系统有什么异常的操作,对510号发生故障的时段(2023分-202758秒)的归档日志进行了LOGMINER分析(故障发生在510202617秒,510202756秒恢复),发现2617秒到2756秒之间没有任何SQL语句执行,说明这个期间数据库完全HANG住(一般情况是发生了Internal Deadlock或者系统内部资源不足造成的等待某资源释放)。在23分到2617秒之间有一个类似DDL操作的迹象,510202610秒,对产生了大量internal操作和对SEG$TSQ$的操作,由于操作是Internal的,因此具体发生了什么DDL操作无法判定。因此无法确定该操作和系统 HANG住是否有直接的联系。可以确认的是,该操作和段扩展没有关系。除此之外,在整个分析时段中没有明显异常的SQLSELECT操作除外,在LOGMINER中看不到)。在整个分析过程中insert操作十分多。

5、使用KILL -3不能停止该死锁进程的操作,不过能在日志中看到该KILL被该进程捕获,说明该进程并没有死或者僵死。并且通过该进程的TRACE开始时间和捕获到KILL-3操作的时间,可以看出,该进程写TRACE已经超过10分钟了,还没有完成。


通过上述的分析,我们基本上可以定位故障了。本故障的主要原因是由于DEAD LOCK 后会话TRACE的时间过长(系统比较老,根盘IO性能较差,同时SGA又比较大,写入的TRACE文件有数百兆之多。由于在在DUMP信息的时候,需要锁住ENQUEUEHASH CHAINS,从而完成DEADLOCK MAP的生成,因此该闩锁被长时间占用,从而导致挂起整个数据库。
Oracle的死锁检测机制是:当Oracle服务进程在等待某个锁资源的时候,会定期检查等待的锁资源的情况,如果2个周期后发现该资源的状态没有任何变化,该服务进程就启动死锁检测机制。由于死锁检测要需要获得ENQUEUE HASH CHAINS父锁。获取父锁会自动获取所有的子锁。当获取该闩锁后,死锁检测开始。死锁检测是一个十分快的操作,不会引起系统挂起。死锁检测完成后,就要写死锁ORA-0060 TRACE文件。在TRACE文件的最后一部分是PROCESSSTATE报告,在该报告完成前,其持有的闩锁不会释放。
在一般情况下,TRACE文件可以在很快的时间内完成,但是对于占用内存较大的系统,写TRACE的时间会比较长,甚至需要几分钟才能够完成。为了保证写入的数据是一致性的,在进行PROCESS STATE DUMP的时候,需要申请一些共享池和DB CACHE BUFFER相关的闩锁。如果这些闩锁存在竞争,那么写PROCESS STATE DUMP的时间会大大加长,在一个繁忙的系统中,产生一个较大的TRACE文件,甚至出现过超过10分钟的情况。更严重的是在部分情况下还会引起系统内部死锁,导致整个数据库被完全挂起,不能自动恢复。这种情况下,只能杀死死锁检测的进程才能恢复系统。
由于在PROCESS STATE DUMP的时候,死锁检测SESSION会持有ENQUEUE HASH CHAINS父闩锁,因此在这个时候,任何需要申请锁资源(包括Internal Lock)的操作都需要等待。由于CURSOR分析需要申请LIBRARYCACHE LOCK/PIN锁,因此在这种情况下,CURSOR分析会无法进行。因此部分SESSION会报ora-600 [kksscl-inf-inl-loop]故障。
在负载较大的系统,由于存在大量的闩锁竞争,会导致PROCESS STATE DUMP由于闩锁竞争而变得缓慢。而对于PGA较大,存在较多OPEN CURSORPIN过较多DB BLOCK、SESSION,PROCESSSTATE DUMP需要记录的内容较多,写TRACE的时间会加长,也会加大共享池的相关闩锁和DB CACHE的相关闩锁的竞争。
对于这个客户系统系统而言,平均每小时都有死锁产生,最多的时候每小时会产生几十个死锁。而绝大多数死锁是不会导致系统挂起的。通过对TRACE文件的分析,出现HANG住数据库的死锁的时候,系统有以下的特点:

l  死锁出现时,存在大量的INSERTUPDATE操作,系统的一致性读(CR GET)十分大

l  死锁出现时,系统中都有大型的SQL存在,这种SQL的特点是都是大型的SELECT操作,存在大量的大表连接,平均每次执行要进行几千万甚至超过1亿个BUFFER GET(也就是说要扫描几个G的数据库缓冲区)。由于在SELECT操作进行的时候,系统的修改操作也十分多,因此会导致SELECT操作产生了大量的CR GET,加大DB CACHE 相关的闩锁竞争

l  死锁出现时,DB BUFFERS CHAINS闩锁竞争比较大

l  死锁的SESSIONPROCESS STATE DUMP比普通DEAD LOCKProcess State Dump

Process State Dump引起HANG住数据库的情况十分复杂,由于DEAD LOCK TRACE引起的数据库HANG住只是其中最常见的一种PROCESSSTATE DUMP故障,目前Oracle公司也没有完整的彻底解决PROCESS STATE DUMP中由于闩锁引起的锁死系统的方法。在这类情况发生比较多的情况下,一般都是采用以下的处理方法:

n  通过调整应用,解决死锁问题

n  关闭TRACE文件中的PROCESS STATE DUMP

n  优化系统,降低系统总体负载,减少故障出现的机会(不能彻底解决问题)

 最后用户采纳了我们的建议,关闭了死锁检测的PROCESS STATE DUMP,采取这个动作后,困扰多时的系统HANG死现象消失了。这说明我们的分析结论是完全正确的。

 




文章转载自白鳝的洞穴,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论