Kill會話過程分析

realkid4發表於2011-01-13

在實際開發中,我們常常需要將使用者的會話強制斷開。比如:事務執行超時、程式碼出現死迴圈、死鎖或者無意中將資料表鎖住。這個使用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 Database 11g Enterprise Edition Release 11.2.0.1.0

Connected as SYS

 

//檢視元件版本:使用SYS登入

SQL> select * from v$version;

 

BANNER

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

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

PL/SQL Release 11.2.0.1.0 - Production

CORE        11.2.0.1.0   Production

 

TNS for Linux: Version 11.2.0.1.0 - Production

NLSRTL Version 11.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=1 Serial#=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         25 5956                     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釋放;

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-683786/,如需轉載,請註明出處,否則將追究法律責任。

相關文章