从 linux 的 dot net core 连接到远程 sql 服务器有时会失败,然后开始随机工作

Connecting to remote sql server from dot net core from linux sometimes fails, then starts working randomly

我在 Ubuntu 18.04 上有一个 C# dotnet core 3.1 Asp.net MVC 申请 运行。它使用 Entity Framework 连接到 Windows Server 2016 上的远程 Sql Server 运行。大多数时候,连接和查询工作正常。然而,偶尔,特别是如果连接应用程序没有收到任何查询数据库的请求,我会收到这个超时错误:

fail: Microsoft.EntityFrameworkCore.Query[10100]
      An exception occurred in the database while iterating the results of a query for context type 'OptionsAPI.Services.OptionsDbContext'.
      System.Data.SqlClient.SqlException (0x80131904): Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
       ---> System.ComponentModel.Win32Exception (258): Unknown error 258
         at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
         at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
         at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
         at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
         at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
         at System.Data.SqlClient.SqlDataReader.get_MetaData()
         at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
         at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
         at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite, String method)
         at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
         at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
         at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
         at System.Data.Common.DbCommand.ExecuteReader()
         at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
         at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
         at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
         at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
      ClientConnectionId:a5e255ac-8539-4e14-96fe-71a7d565cc88
      Error Number:-2,State:0,Class:11
System.Data.SqlClient.SqlException (0x80131904): Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
 ---> System.ComponentModel.Win32Exception (258): Unknown error 258
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite, String method)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.ExecuteReader()
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
ClientConnectionId:a5e255ac-8539-4e14-96fe-71a7d565cc88
Error Number:-2,State:0,Class:11

我不确定为什么会这样。我意识到这有点模糊,但我已经在互联网上搜索了类似的问题,但我不知道下一步该怎么做,所以问了一个模糊的问题。

您是否注意到错误消息是如何显示 "timeout or disconnected" 的?您可能正在为远程 mssql 分配一个 long-运行 操作,而您的客户端设置为不会等待那么久。有一种方法可以在客户端的连接上设置更长或无限期的超时。您可以通过连接字符串或 SqlConnection/SqlCommand 实例上的超时 属性 来执行此操作。如果超时确实是问题,您应该考虑研究如何优化该数据库工作,导致连接打开 10 分钟以上(我认为 10 是默认值),因为任何事情听起来都不太好。

另外调查一下你没有以某种方式引用一些与你的 sqlclient(而不是 dotnetcore)相关的 .Net Framework 包 - 我觉得奇怪的是在那个错误的堆栈跟踪中提到了 Win32,这似乎是全部与客户端上发生的过程相关。也许有些东西不完全兼容。查看是否有 EF 核心包的更新。我知道上次我使用它时他们有错误,所以我不会感到惊讶。

或者,检查您对 OptionsDbContext 实例的使用情况,并确保在完成数据库工作后 closing/disposing/destroying 它是您的。 EF 的 DbContext 旨在仅用于单个工作单元,不应保留在其他线程或未来 processes/requests 中使用。如果您正在使用 DI,请确保该实例和任何其他使用它的实例都没有注册为单例。您的错误表明这可能是忘记(未关闭)连接的结果,该连接最终会断开(默认情况下,由客户端在 10 分钟后),并引发该异常作为副作用。