程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle數據庫基礎 >> 父子進程數據庫連接

父子進程數據庫連接

編輯:Oracle數據庫基礎
 

求助
大約fork到760個進程的時候,數據庫就拒絕連接了
程序基本上就是主程序fork一個子進程,然後子進程操作數據庫後退出
-12549:ORA-12549: TNSperating system resource quota exceeded

這是我的代碼

#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <netinet/in.h>
EXEC SQL INCLUDE sqlca;
EXEC SQL INCLUDE oraca;
EXEC ORACLE OPTION (ORACA=YES);
EXEC ORACLE OPTION (RELEASE_CURSOR=YES);
#define SQLCODE sqlca.sqlcode
int main(void)
{
int conFlag=10000;
int t;
while(conFlag>0)
{
conFlag--;
usleep(1000*100);
//sleep(1);
/*創建新的連接 */
if(fork()==0)
{ /*子進程代碼 */
printf("sleep ok[%d]\n",conFlag);
printf("process start[%d]\n",conFlag);
startProcess();
printf("process quit[%d]\n",conFlag);
exit(0);

}

else
{
}

}

exit(0);
}
int startProcess()
{
sql_context context;
struct sqlca sqlca; /* 需要在此定義一個局部的sqlca */
char uid[] = "maps/maps";
/* 以下SQL語句的執行順序不能更改 */
EXEC SQL ENABLE THREADS;
EXEC SQL CONTEXT ALLOCATE :context;
EXEC SQL CONTEXT USE :context;
EXEC SQL CONNECT :uid;
if(SQLCODE<0){
printf("創建數據庫連接失敗,%d:%s\n", SQLCODE,sqlca.sqlerrm.sqlerrmc);
return -1;
}
insert_data( context );
EXEC SQL COMMIT WORK RELEASE;
if(SQLCODE<0){
printf("斷開數據庫連接失敗!%d:%s\n",SQLCODE,sqlca.sqlerrm.sqlerrmc );
return -1;
}
EXEC SQL CONTEXT FREE :context;

return 0;
}
int insert_data( context )
{
struct sqlca sqlca; /* 需要在此定義一個局部的sqlca */
int i;
int msg_seq;
EXEC SQL CONTEXT USE :context; /* 指定執行SQL語句的上下文 */
for(i=0; i<2; i++ ){
EXEC SQL select SMP_ID_SEQ.NEXTVAL into :msg_seq from DUAL;
if(sqlca.sqlcode!=0)
{
printf("取序列號失敗!%d\n",sqlca.sqlcode);
return -1;
}

EXEC SQL insert into smp_msg_store values(:msg_seq,1,1,:i);
if(SQLCODE!=0){
printf("插入紀錄失敗!%d:%s\n",SQLCODE,sqlca.sqlerrm.sqlerrmc);
return -1;
}
}
}

回復:

my god,數據庫連接數太多。

你應該使用多線程共享有限的數據庫連接,用連接池,要用就取一個,用完了就釋放。
不過這不是proc的強項
alter system set processes = XXXXX
更大的一個數,就可以了
不過正如樓上說的,用連接池吧。
proc是可以
編譯時候加上連接池選項就可以。
不過我記不清楚了。你查查proc的手冊吧

嘿嘿,搞定了,其實是忘了waitpid
至於connection pool,要是java還考慮考慮,這是unix下的c,還是算了

===================================================================

UNIX下數據庫編程的一個錯誤:Fork Function Failed
引言 最近在調試一個數據庫應用程序,發現了一個問題。先不急著說這個問題,先把應用的背景介紹一下。這個應用是朋友的一個程序,運行在Aix Unix系統上,使用了數據庫Oracle9i,而且是網絡程序,需要從網絡接收大量的數據。其基本功能就是從網絡端口接收數據並存儲在存儲空間上,然後把相關的信息寫入到數據庫中。本來這個程序是很簡單的,功能清晰、結構簡單。但是還是出了問題。其症狀是當這個程序運行了兩三天後,就不響應任何請求,遠程登錄到系統上後,不論執行哪種操作,包括ls, ps等,都出現了“The fork function failed, too many processes already existed.”的信息,並拒絕任何操作。
初步分析 根據系統提示的信息,很容易考慮到是程序耗盡了線程資源。令人不解的是該程序僅僅在系統中啟動了5個進程,此外沒有任何的線程操作。僅從程序邏輯上無法看出問題所在。想起了我的拿手好戲,對了,``Google''一把。然而就是這個"google"誤導了我。從我檢索到的資料,我發現大多數人都認為是AIX操作系統對單個用戶的最大進程限制過於嚴格的原因,因此一般的解決方法就是通知系統管理員,給該用戶分配更大的進程資源,或者更改內核參數,提高單用戶的最大進程限制值。
於是我就興奮的跑過去,打開終端,敲入命令,查看用戶的進程數。
ps -ef | grep $USER | wc -l


結果發現進程數據只有20多,再查看系統分配給該用戶的線程資源
smitty chgsys


發現maxuproc的值是500,對於我的程序運行是足夠了。看來問題不是出在這裡。困惑中...
進一步的分析和測試 首先,可以確定系統的線程資源對於運行這個程序是足夠的,其次,根據Shell給出的信息又明顯是進程資源耗盡的結果,那麼結論似乎只有一個,那就是這個程序的運行導致了系統產生了很多的僵屍進程。為了驗證這個分析,我啟動該程序,然後檢查僵屍進程的數量:
ps -ef |grep $PRGNAME | grep defunct | grep -v grep |wc -l


結果,程序一運行,就產生了一個僵屍進程。隨著程序的不斷運行,僵屍數目不斷的增加。因此,這就是罪魁禍首。問題是,這個僵屍進程是從哪裡來的呢?
考慮到程序一執行就會產生僵屍進程,而且後面會源源不斷的產生新的僵屍進程,分析一下程序的邏輯,就會發現與此類似的操作只有一個,那就是與數據庫的連接。因為該程序運行開始會連接數據庫取出運行時所需的配置參數,然後在運行的過程中也會不斷的把數據寫入到數據庫中,因此,我斷定,必定是程序與數據庫的連接導致了僵屍進程的產生。
把程序中的數據庫連接語句全部注釋掉,重新啟動程序,系統的中的僵屍程序沒有出現,再次驗證了我的推斷。馬上聯到Oracle的網站,查查是不是Oracle數據庫的一個Bug,結果沒有發現。繼續Google,發現了這麼一句話:
====================
Hang during "repetitive connect/open/close/disconnect" test:
From: "Alexi S. Lookin"
In short, this problem was solved after addition of parameter BEQUEATH_DETACH=YES in SQLNET.ORA and restarting Oracle instance.
Browsed Net8 doc (A67440-01 Net8 Admin Guide for Oracle 8.1.5, Feb.1999) and found some mention of inadequate bequeath behaviour when disconnecting bequeath session, and some solution for this problem at page 10-15 (may vary at any other release) :
"p.10-15
Child Process Termination
Since the client application spawns a server process internally through the Bequeath protocol as a child process, the client application becomes responsible for cleaning up the child process when it completes. When the server process completes its connection responsibilities, it becomes a defunct process. Signal handlers are responsible for cleaning up these defunct processes. Alternatively, you may configure your client SQLNET.ORA file to pass this process to the UNIX init process by disabling signal handlers.
Use the Net8 Assistant to configure a client to disable the UNIX signal handler. The SQLNET.ORA parameter set to disable is as follows:
bequeath_detach=yes

This parameter causes all child processes to be passed over to the UNIX init process (pid = 1). The init process automatically checks for "defunct" child processes and terminates them.
Bequeath automatically chooses to use a signal handler in tracking child process status changes. If your application does not use any signal handling, then this default does not affect you."
===================
 

這段話的大意就是說,當編程訪問Oracle數據庫的時候,用戶程序必須負責清理連接後產生的僵屍進程,這是通過編寫信號處理程序實現的。當然也可以不這麼做,另外一個方法就是修改Oracle的系統參數,使得Oracle不發送該信號。
處理的方法 讓系統管理員修改Oracle的參數基本上是不可能的,所以還是要自己處理這個信號。根據水木清華上的一位老兄的建議,在fork子進程之前,“signal(SIGCHLD, SIG_IGN);”就行了。或者自己寫signal handler,如果你想獲得更多的信息。

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved