2015-09-27 149 views
5

我们在Windows 2008 SP2/IIS 7上托管的C#WCF Web服务访问Oracle数据库。通常的数据访问工作正常,但负载测试过程中,经常超时和日志和异常说:用于.NET的Oracle数据提供程序:连接请求超时

Error occurred when processing XXXXXXXX Web Service 
Oracle.DataAccess.Client.OracleException Connection request timed out at Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure, Boolean bCheck) 
    at Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, Object src) 
    at Oracle.DataAccess.Client.OracleConnection.Open() 
    at MyWorkspace.WorkForceDataAccess.CheckStaffIdInRSW() 
    at MyWorkspace.MyClass.MyFunction(MyDataType MyData) 

查询数据库,我们使用这样的事情:

OracleConnection orConn = new OracleConnection(); 
orConn.ConnectionString = "user id=xxx; password=xxx; Connection Timeout=600; Max Pool Size=150; data source= (DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = MYHOST.MYDOMAIN.com)(PORT = 1771)) (CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = MYSERVICE.MYDOMAIN.com)))"; 
orConn.Open(); 

using (var cmd = new OracleCommand("MY_UTIL.check_StaffIdInRSW", orConn) { CommandType = CommandType.StoredProcedure }) 
{ 
    cmd.Parameters.Add("P_Staff_Id", OracleDbType.Int32); 
    cmd.Parameters["P_Staff_Id"].Direction = ParameterDirection.Input; 
    cmd.Parameters["P_Staff_Id"].Value = Convert.ToInt32(MyDataObject.StaffId); 

    cmd.Parameters.Add("P_retvalue", OracleDbType.Int32); 
    cmd.Parameters["P_retvalue"].Direction = ParameterDirection.Output; 

    cmd.ExecuteNonQuery(); // Execute the function 

    //obtain result 
    returnVal = int.Parse(cmd.Parameters["P_retvalue"].Value.ToString()); 
} 

我非常有信心被调用的存储过程并不是一直占用的。这是一个非常简单的过程,可以快速检查表中是否存在P_Staff_Id并返回结果。

此外,这仅在负载测试期间发生。在正常的操作过程中,事情没有问题,但是在负载很重的情况下,每秒发送1条消息,这会在运行平稳一段时间后发生。

作为一种变通方法,我已经加入“连接超时= 600;最大池大小= 150“ 到连接字符串,但没有解决问题

我们已经在开发服务器上运行相同的应用程序。它工作正常。我们从来没有遇到过这种问题存在。

任何建议,什么尝试将不胜感激。它看起来像我跑出来的选择。

+0

堆栈跟踪表明,程序不是问题。在Connection.Open内部执行之前引发异常,所以看起来数据库机器已经过载,所以在超时期限内它不能响应客户端。它不应该与Oracle中的池大小或进程限制相关,这些会引发不同的例外。此外,我会怀疑该池的大小,因为将池数量大大超过数据库可以使用的数量是没有意义的。或者你有连接泄漏的地方。 – Husqvik

+0

在发生此问题后,我将连接超时和最大池大小添加到连接字符串 - 但它没有帮助。 Web服务在DEV环境中工作正常,但没有这些。通过连接泄漏,你会建议在使用OracleConnection对象后明确地关闭并处理它吗? – DjD

+0

广告连接泄漏 - 如果连接对象在单个函数中只有短暂生存,那么使用(var connection = ...){...}绝对是更安全的。但我不认为这是问题。当池被完全使用时,你会得到不同的异常。 广告负载测试 - 我期望您可以并行运行应用程序或功能的许多实例。也期望您使用专用连接,而不是Oracle设置的共享服务器。您可以在测试期间检查会话在数据库中的外观,以查看实际有多少会话以及多少个活动会话。 – Husqvik

回答

4

我们也有类似的问题,并花了一段时间来调试和解决这个问题,我们的代码被强调许多输入文件和许多线程处理,每个都是d使用实体框架并打开Oracle数据库连接,并执行一些数据库查询和插入,用于偶尔文件。但大部分时间都适用。

我修改了DbContext构造函数来明确地打开OracleConnection。我加了一些这样的代码

for (i = 0; i < 5; i++) 
    try { 
     oracleConnection.Open(); 
    } catch (OracleException) { 
    Sleep for 15 ms and retry. 
    On last attempt I also do OracleConnection.ClearAllPools() 
    } 

它改进了,但还是没有完全解决。我从调试器中抛出catch,并看到很多线程正在尝试打开,并且很少有线程正在处理。 On在Oracle堆栈中打开时,Oracle为其内部目的执行ThreadPool.QueueUserWorkItem并等待其完成。我可以看到它的等待。这里有大量的连接池可用(默认是100),我很少使用10.所以它没有资源不足。

但问题是在我们的代码中我们还使用了ThreadPool.QueueUserWorkItem而没有额外的限制。我认为把所有需要做的工作排在一起很酷,我们需要多少工作,并让.NET处理这个问题。但这有一个微妙的问题。我们所有的工作都消耗了完整的队列数。当OracleConnection想要从池中获取池连接时,它也会排队到线程池。但它永远不会完成。我们的工作都在等待OracleConnection.Open,它的Queued Thread proc仍然在队列中。所以最后等待会在超时后退出。 很遗憾,尽管有大量的连接池可用,但我们已经使用了所有的ThreadPool进程,Oracle的线程池甚至没有机会。这里设置ThreadPool.SetMaxThreads也无济于事。问题仍然是一样的。我们占用了所有的线程池资源,Orcale不会找到它,并且仍然在队列中。

修复不是只依赖于ThreadPool,但我们也添加了我们自己的限制。我使用了BlockingCollection和sempahores,并在ThreadPool中只添加了一些并发作业的数量,例如5。这样,OracleConnection将始终找到可用的ThreadPool线程,并且不会失败。

1

尝试在最后添加connection.close()。 我没有看到在你的代码中释放连接并显式地将它们返回到连接池。 仅当GC启动时才会将连接返回到连接池。

+0

我们实现了这样的连接。 close()可以明确地关闭连接,并且这似乎有效。感谢大家的帮助。 – DjD

1

即使我以前更频繁地得到这个问题,甚至使用的Connection.close()

的长期分析如下

  1. 的Connection.close(如提及我学到了一些东西后,后)不处理数据库连接
  2. 连接超时并不意味着这个问题是只有数据库查询
  3. 连接超时也可能是由于连接池中的穷举连接(这是我到达最大的罪魁祸首数据库连接的imum会议)

修复: - 分析了很长时间,但解决方法是仅2分钟

using(DbConnection instance) 
{ 

} 

的如: -

using (DbConnection objDbConnection = new DbConnection()) 
{ 
    ojDbConnection.PersistData(); 
} 

下PersistData();所有数据库操作都像打开,关闭e.tc.将执行

正如我们都知道的“使用”是

try 
{ 

} 
catch() 
{ 

} 
Finally 
{ 
    Dispose objDbConnection; 
} 

简称希望它能帮助,因为它帮助我

相关问题