1

一直在与SqlDataReader争斗加重的错误。此旧代码位于运行Windows Server 2012的AWS服务器上使用.NET Framework 3.5的Visual Basic中。数据库是在Amazon RDS环境中运行的Msft Sql Server。SqlDataReader超时过期奇怪的错误

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

这里是我们的分贝包装发生错误的代码。

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.我们确实将连接 Lifetime = 30添加到了我们的连接字符串,并将该池保持在 附近。
  • 我会看到数千个查询在错误之间成功运行。
  • Windows和.NET都修补为最新。

我坚持一些额外的登录,我学到的一件事情是connection.state =就在调用ExecuteReader之前打开,并在错误发生之后关闭。

为了缓解我建立在一些重试逻辑的问题。如果ExecuteReader没有运行,我就纾解,等一秒钟,然后再次调用它。这每次都有效,但会延迟30秒。我可能会将commandTimeout降到30秒以下,但我真的很感兴趣为什么错误首先发生。

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

有什么建议吗?

回答

0

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

这听起来像是如果工作量或错误累积过多,它无法正确关闭连接。 (这应该发生在你的“使用”语句完成并处理时)。你可以阅读增加错误/重试处理失败,关闭,然后重新打开失败的连接状态等。

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

+0

我在其他项目中也使用过Dapper,也是粉丝。但在这种情况下,它只会将错误推送到该代码中,这无济于事。 Dapper还在打开的Connection上执行ExecuteReader: {0}返回cmd.ExecuteReader(GetBehavior(wasClosed,behavior)); } –

+0

我个人倾向于尝试,但无论哪种方式,一个好的第一步可能是在catch语句中实现连接处理和/或重置状态。 –