本文为笔者“Kill会话过程分析”(http://space.itpub.net/17203031/viewspace-683786 )的续篇。做一些更深入的分析。
我们知道,当需要强制断开一个会话的时候,可以通过SQL命令alter system kill session ‘sid, serial#’;强制的将会话断开。其中,SID为会话的编号,Serial为会话的系列号。这两个值是唯一标志Oracle一个会话。而会话的相关信息,可以通过查询v$session视图来获取到。
根据前文我们的分析,认为alter system kill session命令是存在一些不足的。
首先,kill session命令是在会话层面的强制断开。本质上相当于进行了一个标志,切断了Server Process与会话之间的映射关系。会话所占有的资源是不会直接被回收;
其次,kill session命令在一些特殊场合,应对效果不佳。比如在Oracle Job里面运行的时候,是不能定位到相应的会话对象的。
最后,一些紧急的时候,kill session还存在一些适应性较差的情况。比如当前根本无法登陆SQL命令窗口;
那么,比kill session更有效直接的做法是什么呢?针对Server Process的kill操作,也就是OS操作系统级别的kill。当我们不能够使用alter system kill session或者使用其无效的时候,可以考虑使用这种方法。
首先,我们研究一些Linux环境。选择是专用连接模式。
在没有连接的时候,我们查看连接情况。
[oracle@oracle11g ~]$ ps -ef | grep wilson | grep -v grep
oracle 5583 1 0 02:52 ? 00:00:00 ora_pmon_wilson
oracle 5585 1 0 02:52 ? 00:00:00 ora_vktm_wilson
……(篇幅原因,有省略部分)
oracle 5672 1 0 02:52 ? 00:00:00 ora_q001_wilson
oracle 5700 1 0 02:57 ? 00:00:00 ora_smco_wilson
oracle 5702 1 0 02:57 ? 00:00:00 ora_w000_wilson
在没有连接的时候,进程列表中只能看到实例多个background process的运行情况。此时,我们连入一个客户端。查看进程情况:(为省略篇幅,设置筛选条件)
[oracle@oracle11g ~]$ ps -ef | grep LOCAL | grep -v grep;
oracle 5777 1 1 03:09 ? 00:00:00 oraclewilson (LOCAL=NO)
[oracle@oracle11g ~]$
连入了一个客户端,在专用模式下有一个Server Process与之关联。这里对各列含义略作说明。
第一列表示执行用户Owner,第二列是PID,表示进程的系统唯一编号。第三列表示该进程的父进程PPID编号,就是该进程是由哪个进程启动的。之后有两个时间值,分别为进程启动到现在时间与占用CPU时间。最后一列一般为启动命令行。
其中,我们比较关注的就是PID。PID唯一的标识,如果强制终止这个进程,我们就可以强制的结束会话(皮之不存,毛将焉附)。同时,在OS层面的强制终止,进程会话对应的资源可以直接回收。
在Unix/Linux平台下,可以使用kill -9 PID,实现删除。
[oracle@oracle11g ~]$ kill -9 5777 //终止
[oracle@oracle11g ~]$ ps -ef | grep LOCAL | grep -v grep; //确认
[oracle@oracle11g ~]$
使用后,操作系统进程树上的Server Process被清除。此时,连接的客户端如果发起请求。
//之前建立的连接
SQL> conn scott/tiger@wilson
已连接。
//kill之后,尝试连接
SQL> select count(*) from emp;
select count(*) from emp
*
第 1 行出现错误:
ORA-03113: 通信通道的文件结束 //报错!
使用kill -9命令,还可以对background process进程进行管理,对一些问题进程进行杀死重建,也是我们经常使用的手段。
结论:在Linux平台上,当需要在操作系统级别进行kill的时候,可以使用kill -9命令。
接下来,我们在Windows平台上,就有一些问题了。由于体系结构的不同,Oracle在Windows下实现的实例结构,并不是多进程架构方式,而采用的是多线程模式。Unix/Linux下的background process和Server Process,成为了一个ORACLE.exe进程里的线程。那么,这种情况下,我们如何处理?
为了应对这种情况,Oracle提供了一个为orakill.exe的命令。这个命令本质上和alter system kill session的功能相同,但是不需要登录连接数据库。只需要输入线程编号和SID就可以。
这样,问题转化为我们如果获取到一个线程的线程编号。在Windows平台上,有很多查看线程的工具。如Qslice.exe、QuickSlice.exe以及Pstat。
语法:orakill ;
其中,sid为Oracle的sid号。Thread为会话对应的线程的编号。我们可以通过v$session和v$process的信息获取。
SQL> select b.username, a.spid, b.username, b.sid, b.osuser, b.action
2 from v$process a, v$session b
3 where a.ADDR=b.PADDR and b.username='SYS';
USERNAME SPID USERNAME SID OSUSER ACTION
--------- ------------ ---------- ------------------------------ --------------------------------
SYS 1464 SYS 152 WWW-0E6111DFF74\Administrator Command Window - New
SYS 632 SYS 141 WWW-0E6111DFF74\Administrator Main session
注意下v$process的SPID列。在Linux/Unix环境下,这个列的SPID表示Process的编号。在Windows环境下,这列就表示在ORACLE.exe进程下的线程编号。
我们尝试删除命令窗口线程(SPID=1464)。
C:\>orakill orcl 1464
Kill of thread id 1464 in instance orcl successfully signalled.
命令窗口再次尝试连接时。
SQL> select count(*) from dba_objects;
Warning: connection was lost and re-established
说明:连接被切断。
此外,orakill命令也可以在SQL命令提示中使用。
SQL> host orakill orcl 3140
Kill of thread id 3140 in instance orcl successfully signalled.
SQL>
结论:在Windows平台上,可以使用orakill工具进行session和server的杀死工作。
最后,笔者还要强调一下。无论是kill session还是kill -9操作,都是一种危险的操作,特别是在生产环境下。原因在于,后台进程特别是核心后台进程(PMON,SMON,DBWN,LGWR)如果被误删除,相当于实例死掉,是一件重大事故。在没有确认需要、没有专业人员许可的情况下,尽可能的选取破坏性小的方案进行处理。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-684039/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/17203031/viewspace-684039/