db.SaveChanges() returns 'An existing connection was forcibly closed by the remote host.'
db.SaveChanges() returns 'An existing connection was forcibly closed by the remote host.'
在我们的 Web 应用程序(运行ning on Azure)中,用户上传了几个 XML 文件。这些文件保存在 Azure 云存储中,并在 table 中插入一条记录。
我们还有一个 Web 作业(用 C# 编写)正在查看 table,当插入新记录时,它会从存储中下载 XML 文件,解析它并将数据保存到多个table秒。
这 运行 可以使用超过 2 年。最近我们的客户正在上传更大的 XML 文件(300+ MB),这需要更长的时间来处理,我们 运行 变成 time-out errors
。增加超时后,我们得到 Out-of-Memory errors
。
我们现在正在使用 ZZProjects
中的 BulkSaveChanges
并且我们不再使用 OOM-exceptions
并且作为奖励,节省现在大约需要 17 分钟而不是 3 个多小时。
对于一些(大约 10%)大文件,我们会遇到以下类型的错误:
2018-02-23 01:19:06,993 [1] DEBUG Services.DeclarationService - Ready to save to the db
2018-02-23 01:21:10,778 [1] ERROR DataAccess.ApplicationUoW -
Error in saving data: A transport-level error has occurred when sending the request to the server.
(provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)
System.Data.SqlClient.SqlException (0x80131904): A transport-level error has occurred when sending the request to the server.
(provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)
---> System.ComponentModel.Win32Exception (0x80004005): An existing connection was forcibly closed by the remote host
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.TdsParserStateObject.SNIWritePacket(SNIHandle handle, SNIPacket packet, UInt32& sniError, Boolean canAccumulate, Boolean callerHasConnectionLock)
at System.Data.SqlClient.TdsParserStateObject.WriteSni(Boolean canAccumulate)
at System.Data.SqlClient.TdsParserStateObject.WritePacket(Byte flushMode, Boolean canAccumulate)
at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, String name, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, String transactionName, Boolean shouldReconnect)
at System.Data.SqlClient.SqlConnection.BeginTransaction(IsolationLevel iso, String transactionName)
at System.Data.SqlClient.SqlConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.Common.DbConnection.BeginTransaction()
at DbContextExtensions..(BulkOperation )
at Z.EntityFramework.Extensions.EntityBulkOperation`1.(Action`1 )
at DbContextExtensions.[](DbContext , Action`1 )
at DbContextExtensions.[](DbContext , IEnumerable`1 , Action`1 , List`1 )
at Z.EntityFramework.Extensions.BulkSaveChanges.(DbContext , List`1 , List`1 , Action`1 )
at DbContextExtensions.(DbContext , Boolean , Action`1 , Boolean )
ClientConnectionId:####
Error Number:10054,State:0,Class:20
ClientConnectionId before routing:####
Routing Destination:####,11003
我已经在互联网上搜索了几天,我看到了类似的问题,但它们大多与 MSSMS
等客户端软件有关,并通过重新打开客户端软件解决。我没有在本地使用客户端软件。 Azure 上的所有内容 运行。
我们的网络应用程序中确实有手动重试机制,当我重试失败的 XML 文件时,它一直失败。但是当我 运行 我在本地的网络作业(它只是一个 .exe
)但仍然连接到我的 Azure SQL 数据库和 Azure 存储时,失败的 XML 文件确实得到处理。
我已经明白这是一个非常普遍的错误。如果我能获得有关引发此错误的原因的更多详细信息,那就太好了。但我在 Azure 上找不到更多日志记录。
我正在保存一个可能有多个子对象的对象,这使得拆分对象和保存更小的部分变得非常困难。
尽管 Azure 每周重启几次 (very nice on a production environment ;(
),但在出现上述问题时并没有发生这种情况。
如有任何建议或建议,我们将不胜感激。
关于处理那些大的XML文件,你考虑过先拆分再处理吗?由于文件较小时您从未遇到过问题,因此您可以考虑在将这些文件上传到 Azure 存储之前在客户端拆分这些文件,如 this 文章中所示:
感谢 Azure 支持,问题已找到。在我的错误日志中列出了 connectionId,因此他们可以非常仔细地查看它。他们可以看到连接已打开,一些数据已被检索,然后连接空闲了 30 多分钟。因此,Azure 关闭了连接。
在这段空闲时间里,我们的应用程序正在做一些事情,对于大文件,这需要 30 多分钟。 Azure 工程师建议我们应该添加一个 'KeepAlive' 方法并每 5 分钟调用一次以保持连接打开。
在我们的工作单元中 class 我添加了 private readonly Timer _timer = new Timer(5 * 60 * 1000);
并在其构造函数中:
_timer.Elapsed += (sender, e) => KeepAlive();
_timer.Start();
我们的 KeepAlive 方法只是获取一个小 table:
的行
private void KeepAlive()
{
var dummy = _context.BankAccounts.AsNoTracking().ToList().Count;
Console.WriteLine($@"{DateTime.Now} KeepAlive");
}
我们可以使用 .Take(1)
来增强它,只得到 1 行。
添加这个之后我们终于可以完成我们的大文件了。
希望这对其他人有所帮助。我们花了几周时间 ;)
在我们的 Web 应用程序(运行ning on Azure)中,用户上传了几个 XML 文件。这些文件保存在 Azure 云存储中,并在 table 中插入一条记录。
我们还有一个 Web 作业(用 C# 编写)正在查看 table,当插入新记录时,它会从存储中下载 XML 文件,解析它并将数据保存到多个table秒。
这 运行 可以使用超过 2 年。最近我们的客户正在上传更大的 XML 文件(300+ MB),这需要更长的时间来处理,我们 运行 变成 time-out errors
。增加超时后,我们得到 Out-of-Memory errors
。
我们现在正在使用 ZZProjects
中的 BulkSaveChanges
并且我们不再使用 OOM-exceptions
并且作为奖励,节省现在大约需要 17 分钟而不是 3 个多小时。
对于一些(大约 10%)大文件,我们会遇到以下类型的错误:
2018-02-23 01:19:06,993 [1] DEBUG Services.DeclarationService - Ready to save to the db
2018-02-23 01:21:10,778 [1] ERROR DataAccess.ApplicationUoW -
Error in saving data: A transport-level error has occurred when sending the request to the server.
(provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)
System.Data.SqlClient.SqlException (0x80131904): A transport-level error has occurred when sending the request to the server.
(provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)
---> System.ComponentModel.Win32Exception (0x80004005): An existing connection was forcibly closed by the remote host
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.TdsParserStateObject.SNIWritePacket(SNIHandle handle, SNIPacket packet, UInt32& sniError, Boolean canAccumulate, Boolean callerHasConnectionLock)
at System.Data.SqlClient.TdsParserStateObject.WriteSni(Boolean canAccumulate)
at System.Data.SqlClient.TdsParserStateObject.WritePacket(Byte flushMode, Boolean canAccumulate)
at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, String name, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, String transactionName, Boolean shouldReconnect)
at System.Data.SqlClient.SqlConnection.BeginTransaction(IsolationLevel iso, String transactionName)
at System.Data.SqlClient.SqlConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.Common.DbConnection.BeginTransaction()
at DbContextExtensions..(BulkOperation )
at Z.EntityFramework.Extensions.EntityBulkOperation`1.(Action`1 )
at DbContextExtensions.[](DbContext , Action`1 )
at DbContextExtensions.[](DbContext , IEnumerable`1 , Action`1 , List`1 )
at Z.EntityFramework.Extensions.BulkSaveChanges.(DbContext , List`1 , List`1 , Action`1 )
at DbContextExtensions.(DbContext , Boolean , Action`1 , Boolean )
ClientConnectionId:####
Error Number:10054,State:0,Class:20
ClientConnectionId before routing:####
Routing Destination:####,11003
我已经在互联网上搜索了几天,我看到了类似的问题,但它们大多与 MSSMS
等客户端软件有关,并通过重新打开客户端软件解决。我没有在本地使用客户端软件。 Azure 上的所有内容 运行。
我们的网络应用程序中确实有手动重试机制,当我重试失败的 XML 文件时,它一直失败。但是当我 运行 我在本地的网络作业(它只是一个 .exe
)但仍然连接到我的 Azure SQL 数据库和 Azure 存储时,失败的 XML 文件确实得到处理。
我已经明白这是一个非常普遍的错误。如果我能获得有关引发此错误的原因的更多详细信息,那就太好了。但我在 Azure 上找不到更多日志记录。
我正在保存一个可能有多个子对象的对象,这使得拆分对象和保存更小的部分变得非常困难。
尽管 Azure 每周重启几次 (very nice on a production environment ;(
),但在出现上述问题时并没有发生这种情况。
如有任何建议或建议,我们将不胜感激。
关于处理那些大的XML文件,你考虑过先拆分再处理吗?由于文件较小时您从未遇到过问题,因此您可以考虑在将这些文件上传到 Azure 存储之前在客户端拆分这些文件,如 this 文章中所示:
感谢 Azure 支持,问题已找到。在我的错误日志中列出了 connectionId,因此他们可以非常仔细地查看它。他们可以看到连接已打开,一些数据已被检索,然后连接空闲了 30 多分钟。因此,Azure 关闭了连接。
在这段空闲时间里,我们的应用程序正在做一些事情,对于大文件,这需要 30 多分钟。 Azure 工程师建议我们应该添加一个 'KeepAlive' 方法并每 5 分钟调用一次以保持连接打开。
在我们的工作单元中 class 我添加了 private readonly Timer _timer = new Timer(5 * 60 * 1000);
并在其构造函数中:
_timer.Elapsed += (sender, e) => KeepAlive();
_timer.Start();
我们的 KeepAlive 方法只是获取一个小 table:
的行private void KeepAlive()
{
var dummy = _context.BankAccounts.AsNoTracking().ToList().Count;
Console.WriteLine($@"{DateTime.Now} KeepAlive");
}
我们可以使用 .Take(1)
来增强它,只得到 1 行。
添加这个之后我们终于可以完成我们的大文件了。
希望这对其他人有所帮助。我们花了几周时间 ;)