2013-11-01 73 views
7

該應用程序本身在我以前的question中描述。在DAL方面我用ODP .NET行爲怪異

Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342 

這裏是連接字符串:

User id=usr;Password=pwd;Data Source=database1;Validate connection=True;Connection timeout=8;Pooling=false 

的starange是,有時ODP引發了以下異常:

Oracle.ManagedDataAccess.Client.OracleException (0xFFFFFC18): Connection request timed out 
    in OracleInternal.ConnectionPool.PoolManager`3.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, String instanceName) 
    in OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch) 
    in OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch) 
    in OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword) 
    in Oracle.ManagedDataAccess.Client.OracleConnection.Open() 
    in MySyncApp.DBRepository.GetChangedDataDB(DateTime startPeriod) in D:\MySyncApp\MySyncApp\DB.cs:line 23 
    in MySyncApp.Program.<>c__DisplayClass30.<>c__DisplayClass32.<Synchronize>b__2f(ID id) in D:\MySyncApp\MySyncApp\Program.cs:line 441 

但這個異常後,當我看看甲骨文的會議,我看到實際上連接是活着的和剛剛標記爲INACTIVE!因此,這樣的連接將繼續掛在服務器端,逐漸耗盡可用會話的數量。

沒有什麼特別在我的代碼,只是

public List<DataObj> GetChangedDataDB(DateTime startPeriod) 
{ 
    List<DataObj> list = new List<DataObj>(); 
    using (OracleConnection conn = new OracleConnection(this._connstr)) 
    { 
     conn.Open(); 

     using (OracleCommand comm = new OracleCommand("select data from table(usr.syncpackage.GetChanged(:pStart))", conn)) 
     { 
      comm.CommandTimeout = 10; 
      comm.Parameters.Add(":pStart", startPeriod); 

      using (OracleDataReader reader = comm.ExecuteReader()) 
      { 
       // ..omitted 
      } 
     } 

    } 
    return list; 
} 

這段代碼在Parallel.ForEach循環運行從大量的數據庫,同時拉出數據。甚至可能是三個並行連接到同一個數據庫(從不同部門的企業中抽取出模式的不同部分的數據)。

的Oracle是

Oracle數據庫11g企業版發行11.2.0.3.0 - 64位 生產

同步過程本身觸發上在10秒的時間間隔定時器。如果已經捉迷藏任務,然後下一個任務正在停止:

public static void Synchronize(object obj) 
    {    
     // ... omitted 
     log.Info("ITERATION_COMMON_START"); 

     if (Program.State == "Running") 
     { 
      log.Info("ITERATION_COMMON_END_BY_EXISTING"); 
      return; 
     } 

     lock (Program.StateLock) 
     { 
      Program.State = "Running"; 
     }     

     Parallel.ForEach(Global.config.dbs, new ParallelOptions { MaxDegreeOfParallelism = -1 }, (l) => 
     { 
      Console.WriteLine("Started synchronization for {0}", l.key); 
      DBRepository db = new DBRepository(l.connectionString); 

      Parallel.ForEach(l.departments, new ParallelOptions { MaxDegreeOfParallelism = -1 }, (department) => 
      {      
       DateTime ChangesFromTS = GetPreviousIterationTS; 
       List<DataObj> cdata = db.GetChangedDataDB(ChangesFromTS); 
       // ... doing the work here 
      } 

     } 

     // Finishing work 

     GC.Collect();    

     lock (Program.StateLock) 
     { 
      Program.State = ""; 
     } 

    } 

這裏是定時器定期調用同步任務:

Program.getModifiedDataTimer = new Timer(Program.Synchronize, null, (int)Global.config.syncModifiedInterval * 1000, (int)Global.config.syncModifiedInterval * 1000); 

Global.config.syncModifiedInterval以秒爲單位

ODP行爲本身以同樣的方式當我打開池。它創建的連接數超過了Max pool size指令在連接字符串中允許的相同例外情況。

請告訴我你對這些東西的想法和經驗。


UPDATE

這裏是一塊Oracle跟蹤時引發異常:

(PUB) (ERR) OracleConnection.Open() (txnid=n/a) Oracle.ManagedDataAccess.Client.OracleException (0xFFFFFC18): Connection request timed out 
    in OracleInternal.ConnectionPool.PoolManager`3.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, String instanceName) 
    in OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch) 
    in OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch) 
    in OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword) 
    in Oracle.ManagedDataAccess.Client.OracleConnection.Open() 

更新#2

好像這個連接顯示up b由於滯後連接,如請求建立oracle連接被髮送,但其響應被忽略。或者傳輸到/從服務器傳輸的數據在傳輸到目的地時被破壞。

即使關閉應用程序,連接仍然掛在服務器的會話列表中。當我殺死一個會議時,它會一直掛在列表上,並帶有「KILLED」標籤。


更新#3

Here爲演示應用程序,使得同樣的問題。正如我之前所說的那樣,它出現在糟糕的連接上,您可以使用WANem仿真器來模擬這種連接。 Here是我用於數據庫連接的相同組件。希望你的幫助。

+0

您可以在應用程序發生變化時提供轉儲嗎? – Olivier

+0

@Olivier請參閱我的第三個問題更新。希望它能讓你更容易地重現問題。但是,當然,我可以做個轉儲。 – kseen

+0

你能解決嗎? –

回答

4

您的連接超時時間非常短,一般爲8秒,發出命令時爲10秒,請嘗試將其增加到一分鐘以查看會發生什麼情況。我不知道你的算法有多沉重,但只要一個線程在某個地方失敗並且在少於8秒的時間內完成查詢就足夠了,你就會得到這個異常。

而且,我無法找到文件指出ODP.net不是線程安全的,但我無法找到任何文件說,它要麼,所以如果沒有別的幫助試試這個變化:

Parallel.ForEach(Global.config.dbs, new ParallelOptions { MaxDegreeOfParallelism = -1 }, (l) => 
    { 
     Console.WriteLine("Started synchronization for {0}", l.key); 

     Parallel.ForEach(l.departments, new ParallelOptions { MaxDegreeOfParallelism = -1 }, (department) => 
     {      
      // Now local to the executing thread. 
      DBRepository db = new DBRepository(l.connectionString); 

      DateTime ChangesFromTS = GetPreviousIterationTS; 
      List<DataObj> cdata = db.GetChangedDataDB(ChangesFromTS); 
      // ... doing the work here 
     } 

    } 
0

你有沒有嘗試添加命令超時(方法GetChangedDataDB中的代碼行)?這樣

comm.CommandTimeout = 360; 

我已經創建項目,管理龐大的數據,我也得到了錯誤信息爲你,所以我添加越來越多的CommandTimeout值的東西,那麼它的工作原理,但我不知道你是否遇到了和我一樣的案子。

以另一種方式,我看到您在Parallel.ForEach範圍內有Parallel.ForEach範圍,我認爲您可以嘗試使用任務並行庫修改第二個範圍。你可以在這裏更多的瞭解它http://msdn.microsoft.com/en-us/library/dd537609.aspx

然後你的第二個Parallel.ForEach範圍應該是這樣的

Task task = new Task(() => 
Parallel.ForEach(l.departments, new ParallelOptions { MaxDegreeOfParallelism = -1 }, (department) => 
{ 
    // Now local to the executing thread. 
    DBRepository db = new DBRepository(l.connectionString); 

    DateTime ChangesFromTS = GetPreviousIterationTS; 
    List<DataObj> cdata = db.GetChangedDataDB(ChangesFromTS); 
    // ... doing the work here 
} 
)); //close lambda expression 

task.Start(); 
1

我和F#代碼有同樣的問題。它同時產生許多連接,不使用任務並行庫。我同意flindeberg,Motomoto Pink和你自己的結論,問題是連接請求超時異常之後來自Oracle的連接確認響應。

與其他人一樣,我建議您增加連接請求超時。但是,除此之外,你可以考慮使用連接池,將Min Pool Size參數設置爲打開連接的並行生成線程數。當部門數量很大時,使用連接池可以顯着提高客戶端和服務器端的性能。