【问题标题】:SqlDataReader Timeout expired odd errorSqlDataReader Timeout expired 奇数错误
【发布时间】:2017-08-24 14:50:49
【问题描述】:

一直在用 SqlDataReader 解决一个严重的错误。这段旧代码是在运行 Windows Server 2012 的 AWS 服务器上使用 .NET Framework 3.5 在 Visual Basic 中编写的。数据库是在 Amazon 的 RDS 环境中运行的 Msft Sql Server。

我们开始在日志中看到此错误:
“超时已过期。在操作完成之前超时时间已过或服务器没有响应。” 错误堆栈中的最后一个条目是:
在 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。我们确实添加了这个连接 Lifetime=30 到我们的连接字符串,这使池保持关闭 大约 100 个。
  • 我会看到数以千计的查询在错误之间成功运行。
  • Windows 和 .NET 均已更新。

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

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

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

有什么建议吗?

【问题讨论】:

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


    【解决方案1】:

    这使用了一个非常简单的 ADO 实现,正如您正确地指出的那样,它有时并不能很好地处理连接池、连接状态等。

    听起来,如果繁重的工作量或错误正在累积,则无法正确关闭连接。 (这应该在您的“使用”语句完成并处理时发生)。您可以阅读有关在故障周围添加更多错误/重试处理、关闭然后重新打开失败的连接状态等方面的内容。

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

    【讨论】:

    • 我在其他项目中使用过 Dapper,也是一个粉丝。但在这种情况下,它只会将错误推送到该代码中,无济于事。 Dapper 还在打开的连接上执行 ExecuteReader:{ return cmd.ExecuteReader(GetBehavior(wasClosed, behavior)); }
    • 我个人倾向于尝试,但无论哪种方式,第一步都可能是在您的 catch 语句中实现连接处置和/或状态重置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    • 2013-05-30
    • 2013-12-21
    • 1970-01-01
    相关资源
    最近更新 更多