Kill会话过程分析

    技术2024-12-17  11

    在实际开发中,我们常常需要将用户的会话强制断开。比如:事务执行超时、代码出现死循环、死锁或者无意中将数据表锁住。这个使用kill session是很实用的方法。那么,kill session的时候,系统究竟发生了什么呢?

     

    基础知识

     

    用户连接到数据库,涉及到几个对象。首先是监听器,我们常常使用的本地命名服务(tnsname.ora),实际上连接的就是监听器。但是,对于我们连接过程来说,与监听器打交道的时间还是很短暂的(详细可以见笔者其他讨论监听器和连接的文章)。其次是Server Process,是客户端应用在数据库服务器上的操作代表。所有对于数据库实例、数据文件和SGA的操作,实际执行都是Server Process来进行的。最后就是以PMON为代表的后台进程(影子进程),他们负责管理实例的方方面面,保证各方面职能正确实现。

     

    另一个逻辑层次上,用户会话session是一个重要概念。在特定的情况下,我们可以说用户与数据库的交互,就是在一个持续的session中完成。在一个session中,用户可以执行多个事务,可以处在闲置状态(Inactive)。

     

    在任何情况下,如果我们强制性的断开连接,放开session(主动)。PMON后台进程会主动的做回收处理工作(在繁忙的时候存在延时)。回收包括清理会话信息,回滚未提交事务,释放Server Process资源(专用模式下)。

     

     

    在一些时候,我们可以借助alter system kill session ‘sid, serial#’;来手工强制断开用户连接。那么,Oracle进行kill的时候,究竟发生了什么呢?让我一起来研究。

     

    实验环境构建

    Connected to Oracle Database11gEnterpriseEdition Release11.2.0.1.0

    Connected as SYS

     

    //查看组件版本:使用SYS登录

    SQL> select * from v$version;

     

    BANNER

    --------------------------------------------------------------------------------

    Oracle Database11gEnterpriseEdition Release11.2.0.1.0 - Production

    PL/SQL Release11.2.0.1.0 - Production

    CORE       11.2.0.1.0  Production

     

    TNS for Linux: Version11.2.0.1.0 - Production

    NLSRTL Version11.2.0.1.0 - Production

     

     

    首先,为了简便,笔者启动了PL/SQL Developer,并且打开一个Command窗口。之后,启动一个sqlplus窗口,观察这个窗口对应的会话情况。

     

    sqlplus窗口中。

     

    SQL> conn scott/tiger@wilson

    已连接。

     

     

    观察会话情况,查询v$session

     

    SQL> select saddr, sid, serial#, paddr, username, program,action,status from v$session where username in ('SYS','SCOTT');

     

    SADDR     SID   SERIAL# PADDR   USERNAME  PROGRAM        ACTION STATUS

    -------- ----- ---------- -------- ---------- --------------- --------------- --------

    382F0074    1        64 38BC6C94 SCOTT     sqlplusw.exe                   INACTIVE

    382B30C0   24        80 38BC61BC SYS       plsqldev.exe   Main session   INACTIVE

    3829B2F4   33        10 38BC8244 SYS       plsqldev.exe   Command Window ACTIVE

                                                                 - New          

     

     

    可以发现,会话中多了三个session。两个用户名SYS的会话是PL/SQL Developer开启的(原理见之前博客内容)。另一个SCOTT用户开启的sqlplusw.exe是我们的实验对象,发现其sid=1Serial#=64。会话对应的Server Process物理地址为38BC6C94

     

    之后,我们查找的对应的server Process信息,从v$process

     

     

    SQL> select addr,pid,spid,username,serial#,program from v$process where addr='38BC6C94';

     

    ADDR           PID SPID                    USERNAME     SERIAL# PROGRAM

    -------- ---------- ------------------------ ---------- ---------- -------------------------

    38BC6C94        25 5803                    oracle            23 oracle@oracle11g

     

     

    我们可以看出,Scott用户会话SID=1对应的Server Process,进程编号为5803PIDOracle相关进程的内部编号,SPID表示的是操作系统级别)。

     

    最后,我们查看操作系统级别进程信息。

     

    [oracle@oracle11g~]$ ps -ef | grep LOCAL

    oracle   5780    1 0 05:47 ?       00:00:03 oraclewilson (LOCAL=NO)

    oracle   5788    1 0 05:48 ?       00:00:00 oraclewilson (LOCAL=NO)

    oracle   5803    1 0 05:50 ?       00:00:00 oraclewilson (LOCAL=NO) //对于的那个Server Process

     

     

     

    实验kill会话。

     

    在观察PL/SQL Developer里,将SCOTT会话断开。

     

    SQL> alter system kill session '1,64';

    System altered

     

     

    Kill操作执行完成,没有报错。那么,这个会话信息真的被删除了吗?我们重新检查v$session

     

    //发现,会话SCOTTSID=1Serial#=64信息还存在)

    SQL> select saddr, sid, serial#, paddr, username, program,action,status from v$session where username in ('SCOTT');

     

    SADDR     SID   SERIAL# PADDR   USERNAME  PROGRAM ACTION         STATUS

    -------- ----- ---------- -------- ---------- ------------------------- --------------- --------

    382F0074    1        64  38058594 SCOTT  sqlplusw.exe  KILLED

     

    //按照原来的Server Process地址查找Server Process信息还存在;

    SQL> select addr,pid,spid,username,serial#,program from v$process where addr='38BC6C94';

     

    ADDR           PID SPID                    USERNAME     SERIAL# PROGRAM

    -------- ---------- ------------------------ ---------- ---------- -------------------------

    38BC6C94        25 5803                    oracle            23 oracle@oracle11g

     

    “怪事”发生了,我们kill掉了会话。但是会话信息还存在,与刚才的结果区别是两个:其一为会话的状态变为了KILLED状态,表示已经被kill。其二是对应Server Process的地址被修改,该到了38058594的位置上。

     

    而查看v$process进程视图,发现原来为其服务的Server Process信息仍然存在!那么,是真的存在吗?我们查看操作系统层面:

     

    [oracle@oracle11g~]$ ps -ef | grep LOCAL

    oracle   5780    1 0 05:47 ?       00:00:03 oraclewilson (LOCAL=NO)

    oracle   5788    1 0 05:48 ?       00:00:00 oraclewilson (LOCAL=NO)

    oracle   5803    1 0 05:50 ?       00:00:00 oraclewilson (LOCAL=NO)

     

     

    看来Server Process确实存在。那么这个新Server Process地址38058594是什么呢?

     

     

    SQL> select addr,pid,spid,username,serial#,program from v$process where addr='38058594';

     

    ADDR           PID SPID                    USERNAME     SERIAL# PROGRAM

    -------- ---------- ------------------------ ---------- ---------- -------------------------

     

     

    综合上述:在kill的时候,Oracle做了两件事。一件是将会话的状态修改了KILLED,相当于打了一个标记。第二件是通过将会话对应的Server Process地址修改为一个虚拟地址,切断会话信息与Server Process的映射关联。此外,Server Process并没有回收。

     

    等待一会之后,发现依然如此!没有PMON主动的回收动作。

     

    那么,如果此时被kill掉的会话发起一个操作,如何?

     

    sqlplus上:

     

    SQL> select * from emp;

    select * from emp

    *

    1行出现错误:

    ORA-00028:您的会话己被终止

     

     

    被断开的会话拒绝操作,告知说会话已经被终止。

     

    此时,系统还能查看到这个会话信息吗?

     

     

    SQL> select saddr, sid, serial#, paddr, username, program,action,status from v$session where username in ('SCOTT');

     

    SADDR     SID   SERIAL# PADDR   USERNAME  PROGRAM         ACTION STATUS

    -------- ----- ---------- -------- ---------- ------------------------- --------------- --------

    SQL> select addr,pid,spid,username,serial#,program from v$process where addr='38BC6C94';

     

    ADDR           PID SPID                    USERNAME     SERIAL# PROGRAM

    -------- ---------- ------------------------ ---------- ---------- -------------------------

    38BC6C94        25 5803                    oracle            23 oracle@oracle11g

     

     

    结论:当我们在原有窗口执行操作,尝试会话通信时,被拒绝。通过视图查询,发现原有被kill的会话信息被回收。但是Server Process还存在在视图上,但不与任何会话对应。

     

    那操作系统层面上:

     

     

    [oracle@oracle11g~]$ ps -ef | grep LOCAL

    oracle   5780    1 0 05:47 ?       00:00:03 oraclewilson (LOCAL=NO)

    oracle   5788    1 0 05:48 ?       00:00:00 oraclewilson (LOCAL=NO)

    oracle   5803    1 0 05:50 ?       00:00:00 oraclewilson (LOCAL=NO)

     

     

    Server Process还存在,没有回收。

     

    注意:当我们关闭掉sqlplusw窗口之后,也就是我们关掉客户端的时候,我们再次查询发现:

     

    [oracle@oracle11g~]$ ps -ef | grep LOCAL

    oracle   5780    1 0 05:47 ?       00:00:03 oraclewilson (LOCAL=NO)

    oracle   5788    1 0 05:48 ?       00:00:00 oraclewilson (LOCAL=NO)

     

     

    Server Process被回收,v$process自然也应当没有对应记录存在了。

     

     

    SQL> select addr,pid,spid,username,serial#,program from v$process where addr='38BC6C94';

     

    ADDR           PID SPID                    USERNAME     SERIAL# PROGRAM

    -------- ---------- ------------------------ ---------- ---------- -------------------------

    38BC6C94        255956                    oracle            26 oracle@oracle11g(J000)

     

     

    诶,为什么有记录呢?仔细看看:SPID已经发生变化,不是5803,而是5956,是一个新启动的进程。只是使用了刚刚被释放的地址。

     

    结论:驻留在数据库服务器的Server Process会一直存在,直到客户端应用断开连接,不在于Server Process通信。注意,这时如何客户端重新连接conn,客户端是重新与监听器沟通,获取一个新的Server Process重定向,不会找过去的那个旧Server Process。一旦重新登录,旧的Server Process就会被回收释放掉。

     

    综上所述:在kill研究中,我们搞清楚了几个方面问题:

     

    1、alter system kill session:只是将session标记为可以回收,切断会话与Server Process的映射关系。没有进行资源释放回收工作;

    2、一旦尝试连接,PMON会主动开始清理被kill的会话,同时Oracle拒绝连接操作;

    3、Server Process是一个忠实于客户端的进程,只要客户端还在启动,维持着两个之间的联系。Server Process是不会被回收的。直到客户端主动停止与Server Process的通信,Server Process释放;

    最新回复(0)