我们在Windows 2008 SP2 / IIS 7上托管了一个访问Oracle数据库的C#WCF Web服务。通常数据访问工作正常,但在负载测试期间,它经常超时并记录和异常说:
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条消息,这在平稳运行一段时间后就会发生。
作为一种解决方法,我添加了#34;连接超时= 600;最大池大小= 150“连接字符串,但这不能解决问题。
我们在开发服务器上运行相同的应用程序,它运行正常。我们从未在那里遇到过这个问题。
任何关于尝试什么的建议都将受到赞赏。看起来我的选项已经用完了。
答案 0 :(得分:5)
我们遇到了类似的问题,需要一段时间来调试并修复此问题。我们的代码在很多输入文件和许多线程处理上受到压力,每个线程使用Entity框架并打开Oracle数据库连接,并做一堆db查询和插入,偶尔用于文件。但大部分时间都有效。
我修改了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()
}
它有所改进,但仍然没有完全解决。我从调试器中打破了捕获,并看到许多线程正在尝试打开并且很少有线程正在处理。 在Oracle堆栈中打开时,Oracle的内部用途是ThreadPool.QueueUserWorkItem并等待其完成。我可以在堆栈上看到它的等待。这里有大量的池化连接(默认为100),我几乎不使用10.所以它不是资源。
但问题出在我们的代码中,我们还使用了ThreadPool.QueueUserWorkItem,没有额外的限制。我认为排队我们需要做的所有工作,我们需要多少工作,让.NET处理这个问题很酷。但这有一个微妙的问题。我们所有的工作都消耗了完整的队列数。当OracleConnection想要从池中获取池连接时,它也会排队到线程池。但它永远不会完成。我们的所有工作都在等待OracleConnection.Open,它的Queued Thread proc仍然在队列中。所以最后等待将在超时时退出。 遗憾的是,即使有大量的池连接可用,我们已经消耗了所有ThreadPool proc,而Oracle的线程池甚至没有机会。在这里设置ThreadPool.SetMaxThreads也没有帮助。问题仍然存在。我们占用了所有线程池资源,Orcale没有找到一个并且仍然在队列中。
修复不仅仅依赖于ThreadPool,而且我们也添加了自己的限制。我使用了BlockingCollection和sempahores,并在ThreadPool中添加了一些限制数量的并发作业,比如说5.这样OracleConnection总会找到一个可用的ThreadPool线程,并且不会失败。
答案 1 :(得分:1)
尝试在最后添加connection.close()。 我没有看到在代码中释放连接并明确地将它们返回到连接池。 因此,只有在GC启动时才会将连接返回到连接池。
答案 2 :(得分:1)
即使在使用Connection.Close()
之后,我也经常更频繁地解决这个问题经过长时间的分析,我学到了很多东西,如下所述
修正: - 分析需要很长时间,但修复只需2分钟
using(DbConnection instance)
{
}
例如: -
using (DbConnection objDbConnection = new DbConnection())
{
ojDbConnection.PersistData();
}
在PersistData()下;所有数据库操作都像Open,关闭e.tc.将被执行
众所周知,“使用”是
的缩写形式try
{
}
catch()
{
}
Finally
{
Dispose objDbConnection;
}
希望它有所帮助,因为它帮助了我