listener為何要fork兩次子程式

531968912發表於2017-12-19

http://www.itpub.net/thread-1799332-1-1.html 

以下是根據網路資料個人總結的listener監聽流程(如果有誤煩請指正)

大致分為6個階段

1

客戶端向資料庫發起連線請求,listener負責響應接受;

2

Listener程式fork子程式1

如果子程式1執行時間過長,則會導致listener長時間等待(期間不接受其他資料庫連線);如果子程式1異常則listenerhang--這句話質疑著很多,我也只是從相關資料摘抄的,沒有試驗根據

Ps ef | grep tnslsnr顯示的ppid!=1的程式便是

3

子程式1fork子程式2,然後前者退出;

此時listener等待接受子程式2的資料

4

子程式2執行系統呼叫exec oracle,變為oracle server process,其向listener傳送自身後設資料(比如pid)

5

Listenerserver procees傳送客戶端資料,然後寫入listener.log

直到此刻listener任務完成,可以接著處理下一個連線

6

Server process與客戶端互動,完成後續工作

問題:

為何listener要建立fork兩次子程式,直接採用第一個子程式呼叫exec oracle不可以麼?

 

 

以下是回覆,個人受教很多

 

本帖最後由 Yong Huang 2013-6-28 08:48 編輯

It's always a good habit to give reference, unless you find all this out completely from your own test.

I've done such test a long time ago. What you described is basically correct. But this

如果子程式1執行時間過長,則會導致listener長時間等待(期間不接受其他資料庫連線);如果子程式1異常則listenerhang”

is new to me. I'd like to know the source.

The reason why listener needs to fork twice is related to the requirement of a UNIX daemon. The best answer is here:



Basically, if it forked only once, the server (shadow) process would still have a parent i.e. the tnslsnr process instead of init (pid 1). Forking twice, after the first child exits, the second child will definitely become an orphan and then init becomes its parent.

You may ask why bother to make sure the server process is a daemon. I think the answer is just that Oracle wants to make sure the server process is independent of the listener, so if the listener dies, existing server processes continue to function because they're immune from signals that will be sent to the listener.

 

freas

發表於 2013-6-29 00:57:21 |只看該作者

Yong Huang 發表於 2013-6-28 22:46
It's always a good habit to give reference, unless you find all this out completely from your own te ...


有哪些原因會導致僵死程式?
一般認為父程式fork之後,會呼叫wait()函式等待子程式結束,父程式獲取到子程式結束(子程式自己呼叫exit())的資訊後,作業系統核心才徹底釋放一個程式的所有資訊。
這裡分兩種異常情況。1、父程式沒有呼叫wait,從而產生僵死程式。2、父程式由於某些原因,先於子程式退出,子程式成為孤兒程式被init收養,當子程式呼叫exit退出後,成為僵死程式,被init處理掉。
Oracle
採用的double fork策略和第二點比較類似,不過,Oracle的想法比較悲觀,覺得父程式(listener)一定會異常,所以它直接把第一次fork出的子程式手工殺死(fork之後就exit),強制把fork2變成孤兒程式。
至於Oracle為什麼會這麼想,也就無從得知了或許在Oracle的原始碼裡有註釋。但是,這種想法是否是科學的,或者是否是最先進的,保留疑問。
個人猜測,在1020年前,作業系統核心可能還不如現在的穩定健壯,殭屍程式的情況必須考慮在內,所以做出double fork的策略。
但是,double fork是由其副作用的。
首先,一個程式是核心裡非常複雜(消耗資源)的組成。
一個程式要生成,至少需要4個元素:
1
task_struct結構體物件。
2
、程式私有地址空間。
3
、核心態堆疊。
4
、可執行程式碼。
在呼叫fork一個程式的時候,這些資源是需要生成好了,才能生成程式的,exit的時候(準確的說是父程式wait返回或者是僵死程式的資料結構被回收之後),這些資源都是要釋放的,這些過程都涉及到大量資料結構的遍歷以及加鎖(smp下的spinlock)。
Oracle採取了悲觀的暴力策略,不管三七二十一,一來就forkexit,而事實上,這個fork1的程式是啥實事兒都沒做的。假設是oltp系統,假設它的併發量大一點,比如每秒鐘來個上千次連線的,作業系統僅為Oracle就要fork 2k次,exit至少1k次,這個資源消耗就大了。

 

Yong

> Oracle為什麼會這麼想,也就無從得知了

Didn't you already answer this question? "Oracle
的想法比較悲觀,覺得父程式(listener)一定會異常". In case the listener crashes, the server process must be protected from crashing. Although I think it's possible to program the child to not receive any signal delivered to the parent (tnslsnr), it's safer to just fork one more time and let the first child exit.

I haven't checked 12c. But I think somebody says beginning with 12c, Oracle on UNIX/Linux adopts the thread model as on Windows. Hope somebody can check.

 

 

freas

1Oracle採用doule fork主要你是為了預防子程式退出時,listener已經crash了,子程式成為僵死程式沒有解決策略。至於"in case the listener crashes, the server process must be protected from crashing",父程式crash,子程式仍然可以正常執行,只是子程式呼叫exit之後,會成為僵死程式。
2
> Oracle為什麼會這麼想,也就無從得知了

Didn't you already answer this question? "Oracle
的想法比較悲觀,覺得父程式(listener)一定會異常". 我只是從技術層面猜測一下,而且,在上面的猜測裡,double fork的方法作為一個server的網路處理方式,在2013727日看來,弊大於利。
3
、我個人覺得這種double fork的方式更多的是從DBA的管理上來設計的。因為Oracle提供listenerstart/stop/restart介面。如果沒有采用double fork方式,一旦listener stop了,所有的server process必然成為孤兒程式(此時,server process可能正在執行復雜的transaction,風險太大),而server process顯然不應該在正式幹活的時候受到listener的執行狀態的影響,所以直接在一開始就把這個有風險的操作主動做了,掌握控制權(哎,這種說法太意淫了)

 

 

 

 

 

 

 

 

 

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

相關文章