Azure SQL 单数据库 DTU 超时错误。

5
我正在使用Azure SQL购买单一数据库DTU模型。平均负载似乎低于10%。不时会收到错误,现在几乎每天都会发生。我正在使用EF Core 3.1来访问数据库。该数据库从使用ASP.NET Core 3.1构建的API访问,并部署在Linux Azure应用服务上。
错误信息如下:
执行超时已过期。 操作完成之前超时时间已过或服务器未响应。 ---> System.ComponentModel.Win32Exception (258):未知错误258

堆栈跟踪:

An exception occurred in the database while saving changes for context type 'MTP.Api.Persistence.MTPDbContext'.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
 ---> Microsoft.Data.SqlClient.SqlException (0x80131904): Execution 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 Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__164_0(Task`1 result)
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
ClientConnectionId:16f899d4-cfc9-4401-b631-1b4d547c4c19
Error Number:-2,State:0,Class:11
ClientConnectionId before routing:02e37a1e-981c-4ff6-9437-cade8b401cc5
Routing Destination:c71faab34237.tr1.francecentral1-a.worker.database.windows.net,11018
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)

有什么想法可以导致这个问题吗?或者我如何找到导致问题的原因?

打开查询存储并监视查询执行时间和等待统计信息。https://learn.microsoft.com/en-us/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store?view=sql-server-ver15 这是一个客户端超时,您可以延长它:https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.relationaldatabasefacadeextensions.setcommandtimeout?view=efcore-3.1 - David Browne - Microsoft
谢谢David,我会打开查询存储。超时时间已经是30秒了。 - Emanuel Paul
您可能需要延长超时时间以捕获等待统计信息,因为我认为它们只会被捕获完成查询的查询。SQL Azure默认启用查询存储。查询计划选择可能是一个因素,所以如果您卡住了,请发布它。 - Conor Cunningham MSFT
我会增加超时时间。这个错误似乎只在Azure SQL上出现,在SQL Server 2017 Express上似乎工作正常。 - Emanuel Paul
涉及到的表有多大?如果很大,那么出现这种偶发错误的可能性之一就是统计更新(如果它们没有设置为异步更新)-对于任何大小的表,另一个可能性是来自其他事务的阻塞。 - Martin Smith
这些表格非常小,用于读写的最大表格约为2-3 MB。有一个表格大小为117 MB,但仅用于读取数据。 - Emanuel Paul
2个回答

4

我将nuget包Microsoft.Data.SqlClient更新到2.0版本,看起来这解决了问题。

API正在使用EF Core 3.1。EF Core正在使用MARS(MultipleActiveResultSets)。在Linux上部署并使用MARS时,Microsoft.Data.SqlClient版本1.0似乎存在问题。EF Core默认使用v1。


0

这可能与发送多个请求时出现EF Core异常#13452有关:

I updated my project to ASP.NET Core 2.1 RTM. When I send multiple requests, i get this exception:

Exception has occurred: CLR/System.Data.SqlClient.SqlException
An exception of type 'System.Data.SqlClient.SqlException' occurred in Microsoft.EntityFrameworkCore.dll but was not handled in user code: 'Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.'
 Inner exceptions found, see $exception in variables window for more details.
 Innermost exception   System.ComponentModel.Win32Exception : Unknown error 258
@ajcvickers 我发现问题了,SQL Server主机已经接收了两个更新:KB4338815, KB4338824。这个更新存在以下已知问题:重新启动SQL Server服务时,可能会失败并显示错误信息“Tcp端口已被占用”。当我删除这些更新后,我的项目就没有问题了。

当然,这也可能只是死锁的情况。为了更容易地跟踪此问题,您可能希望记录两种情况:非常缓慢但成功的查询和失败的查询。

在死锁的情况下,至少涉及两个查询。至少一个会超时,但另一个仍可能在超时阈值之内,一旦第一个查询被取消,它就会成功。因此,如果您记录两者,就可以追踪死锁的原因。


无论如何,如果您想通常处理此类问题,您可能需要使用options.EnableRetryOnFailure()设置连接弹性,并可能降低命令超时值。这将重试失败的操作。

它在 SQL Server 2017 Express 上似乎运行良好。错误仅在 SQL Azure 上发生。因此,这可能与我收到的错误无关。 - Emanuel Paul
我更新了我的答案,加入了另一个原因和一些通用建议。 - lauxjpn
连接弹性已被使用。我注意到所有表都被阻止了,因此在更改服务计划之前无法对该表执行任何操作。 - Emanuel Paul
请检查服务器端数据库日志以了解情况。另外,“直到服务计划更改”是什么意思? - lauxjpn
在使用SQL Azure时,有多个定价层和购买模式。例如,如果将定价层从20 DTUs更改为50 DTUs,则表将保持锁定(超时错误会发生)。 - Emanuel Paul
你在峰值时有多少并发连接,这些超时是在峰值时间发生的吗?假设存在死锁,可能会导致所有其他连接也被锁定,同时等待其中一个被锁定的表。这将耗尽你的 DTU。其他请求可能仍然排队等待,而第一个请求最终将超时,后续请求可能会继续锁定表格。如果发生超时,您应记录当前使用了多少 DTU,以及是否锁定/死锁了任何表格。 - lauxjpn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接