SqlDataReader超时过期奇怪错误

时间:2017-08-24 14:50:50

标签: .net sql-server database-connection connection-pooling sqldatareader

与SqlDataReader打了一个加重的错误。此旧代码在运行Windows Server 2012的AWS服务器上使用.NET Framework 3.5在Visual Basic中。数据库是在Amazon的RDS环境中运行的Msft Sql Server。

我们在日志中开始看到此错误:
“超时已过期。在操作完成之前已经过了超时时间,或者服务器没有响应。” 并且错误堆栈中的最后一个条目是:
at System.Data.SqlClient.SqlCommand.ExecuteReader()

以下是我们的db包装器中发生错误的代码。

Try
   Using connection As New SqlConnection(dbConnStr)
      connection.Open()
         Using command As New SqlCommand(sql, connection)
            Using dataReader As SqlDataReader = command.ExecuteReader()
               Do While dataReader.Read()
                  'do stuff with the results here
               Loop
             End Using
      End Using
   End Using
Catch
   'write error to log here
End Try
  • 这个系统背后的数据库肯定在工作。我跑了一下,看到大量的查询被调用。还带着一条痕迹 过滤为仅显示大约5秒的查询,并且没有。
  • 触发错误的查询是随机的,从不相同。当我看到错误时,我可以从日志中获取查询并运行它 手动,并快速/成功运行。
  • 跟踪还表明查询永远不会在数据库中运行。
  • 由于我们在AWS中运行,我们启动另一台服务器并将AMI恢复到它,并遇到同样的问题。
  • 错误开始累积后,我们的连接池爆炸了。我们的连接池设置为700.我们确实添加了此连接 生命周期= 30到我们的连接字符串,这使池保持不变 大约100。
  • 我会在错误之间看到成千上万的查询成功运行。
  • Windows和.NET都是最新修补的。

我添加了一些额外的日志记录,我学到的一件事是connection.state =在调用ExecuteReader之前打开,而在发生错误之后就关闭了。

为了缓解我在某些重试逻辑中构建的问题。如果ExecuteReader没有运行,我会拯救,等待一秒钟,然后再次调用它。这种方法每次都有效,但会引入30秒的延迟。我可能会将commandTimeout降低到比30秒更烦人的事情,但我真的很感兴趣为什么错误发生在第一位。

我决定的一件事是连接池处理是艺术而不是科学。在这种情况下,我们的结论是与数据库的连接以某种方式变得腐败。我们推测新的连接生命周期设置有助于回收池并防止它爆炸,这很好,因为它可以防止这个网站崩溃。

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

这使用了一个非常简单的ADO实现,正如您所正确识别的那样,它有时并不能真正处理连接池,连接状态等。

听起来好像繁重的工作量或错误正在累积,它无法正确关闭连接。 (这应该在您的“使用”声明完成并处置时发生)。您可以阅读有关添加更多错误/重试处理失败,关闭然后重新打开失败的连接状态等的信息。

最简单的解决方案可能是实现一个ORM(我个人喜欢Dapper,但选择最适合你的东西)来处理所有这些东西 - 它可能比尝试重新发明更好更容易轮。