处理EXP导出HANG住问题一例

论坛求助

    上周CD渠道的ZSL联系我,让我看一下他在论坛上发了一个求助帖《oracle11.2.1全库导出不能使用,告知我这是工作中实际遇到的问题,由于这个原因,用户的数据已经几天没有备份了,用户的数据安全无法得到保障,希望我能协助帮忙处理,由于电话指导比较麻烦,用户又有远程环境,于是我提议进行远程处理。

问题重现

    远程桌面连接到用户处,首先得看一下问题现象,做了一个全库的逻辑备份,确实如其描述的一样,当逻辑备份执行到如下图所示的位置,就一直Hang在那里,几分钟都没有动弹,导致全库备份无法成功。

    通过现象,我们可以分析这是一个典型的资源等待导致,因此我们需要先从ORACLE的等待事件中查找导致问题的原因。

思路分析

    首先肯定是要找到该逻辑导出的会话,通过查询V$SESSION视图,指定program字段为‘exp.exe’执行文件查找,得到结果如下图:

    通过查询的结果,发现居然有2条记录,不过状态不同,sid为148的记录状态是KILLED,sid为213的记录状态为ACTIVE,询问现场工程师,得知148是其几天前执行逻辑备份时,由于有其他操作,技术人员手工直接杀掉会话导致,但是在视图中,其一直保持KILLED状态,而sid为213这个会话是当前执行的逻辑备份会话。经过观察,确实如其所说,接下来我们就需要重点分析下sid为213这个会话,为什么其会hang住,我们需要查下他目前是在等待什么操作,这个我们可以通过查询v$session_wait会话查看,查询下sid为213的会话目前的等待事件为什么,结果如图:

    这里我们看到了一个等待事件‘library cache lock’,那么什么情况下会出现library cache lock,这里我们首先要了解什么是Library Cache。

    Library Cache是Oracle SGA 中Shared pool 的组成部分,它几乎是Oracle内存结构中最复杂的一部分,主要存放shared curosr(SQL)和PLSQL对象(function,procedure,trigger)的信息,以及这些对象所依赖的table,index,view等对象的信息,Library cache主要解决这些对象的三个问题:1.快速定位,2.关系依赖,3.并发控制,其中并发控制就会涉及到library cache lock,当会话访问对象时,首先必须获取lock,然后将访问的数据pin在内存中。lock的作用是控制进程间的并发访问,而pin的作用是保证数据一致性,防止数据在访问时被交换出去,了解到了这个情况,我们就需要查询到是那个会话把该逻辑备份的会话堵塞,只要找到这个堵塞会话,然后加以解决,相信该Hang的问题就能够随之解决。

解决过程

    如前面提到的,首先是找到什么会话导致library cache lock ,这里我们需要用到metalink的一篇文章《How to Find which Session is Holding a Particular Library Cache Lock [ID 122793.1]》,该文详细介绍了如何找到导致holding的会话,大意是说要使用的到oracle的x$内部表,有兴趣的同学可以自己查看下该文章,我这里直接引用。

    x$表是oracle的内部核心表,只有sys用户连接数据库才能访问,通过下面的一段SQL查出堵塞会话。

    这里我眼前一亮,SID为148的会话,不正事前面我们查询出来状态为KILLED的会话吗?看来已经确定是该会话导致后续的exp堵塞,那既然已经杀掉的会话,为什么还会堵塞呢?这里我们有必要说明下oracle的kill会话的操作。

   在Oracle数据库中,可以通过kill session的方式来终止一个进程,语法为:

alter system kill session 'sid,serial# ',但是alter system kill session只是将session标记为可以回收,切断会话与Server Process的映射关系。但没有进行资源释放回收工作,一旦尝试连接,PMON会主动开始清理被kill的会话,同时Oracle拒绝连接操作,Server Process是一个忠实于客户端的进程,只要客户端还在启动,维持着两个之间的联系。Server Process是不会被回收的。直到客户端主动停止与Server Process的通信,Server Process才释放资源。如何才能彻底释放资源呢?其实我们只要在操作系统层面上,结束该会话的进程就行了,首先要找到进程号,由于被置于KILLED状态的会话,该session的paddr被修改,因此无法通过v$session和v$process关联来获得spid,但是可以通过下面的SQL语句,来进行查找:

    知道了会话的spid后,就可以通过orakill工具直接在操作系统命令模式下,结束掉该会话。

    C:\>orakill orcl 1639

    Kill of thread id 1639 in instance orcl successfully signalled

    C:\>

    然后再查询v$session,可以看见killed状态的会话已经消失了,堵塞会话已经彻底清除,orakill是oracle提供的windows平台下强制结束oracle进程的工具,这方面的知识有兴趣的同学查看metalink文档《ALTER SYSTEM KILL SESSION does not Release Locks Killing a Thread on Windows NT [ID 100859.1]》,接着就赶快再试试exp导出是否还会Hang住。

验证问题

    立即执行下exp导出,验证下问题是否已经得到解决,正常情况下,在导出系统对象和过程时也会停顿一段时间,这个时候,查询下v$session_wait视图,可以看到等待事件为SQL*Net message from client如下图:

    SQL*Net message from client属于空闲等待,如图,等待类型属于IDLE,已经不再是Library Cache Lock,一般情况下可以不用理会,属于正常的等待事件。过了大概半分钟,开始看到数据表的导出,此致问题得到圆满的解决。

后续总结

    通过本文的介绍,我们不光晓得本例中问题的解决方法,还应该基本了解到处理ORACLE一般Hang住问题的基本思路:

1.首先确定Hang住会话的等待事件。。

2.然后分析该等待事件,找到引起该等待的原因,是由于锁,还是由于资源繁忙?

3.最后根据其产生的原因,排除问题,一般都能够解决问题。

     希望本例的介绍对大家在以后处理类似业务有所帮助。

请使用浏览器的分享功能分享到微信等