2013-11-01 68 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参数设置为打开连接的并行生成线程数。当部门数量很大时,使用连接池可以显着提高客户端和服务器端的性能。