如何解决Azure Kubernetes .NET Core 应用程序到 Azure SQL 数据库间歇性错误 258
我们正在 Kubernetes 集群中运行 .NET Core 3.1 应用程序。该应用程序使用 EF Core 3.1.7 和 Microsoft.Data.SqlClient 1.1.3 连接到 Azure SQL 数据库。
在看似随机的时间,我们会收到以下错误。
---> 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.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.ThrowExceptionAndWarning(Boolean callerHasConnectionLock,Boolean asyncClose)
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj,UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
at System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
at System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
at System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value)
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,Boolean returnStream,Boolean async,Int32 timeout,Task& task,Boolean asyncWrite,SqlDataReader ds)
at System.Data.SqlClient.SqlCommand.ExecuteScalar()
尽管看起来是随机的,但在较重的负载下它肯定会更频繁地发生。从我的研究来看,似乎这个特定的超时与连接超时而不是命令超时有关。 IE。客户端根本无法建立连接。这不是超时查询。
我们已消除的潜在根本原因:
- Azure SQL Server 容量:无论我们在 4 个还是 16 个 vCPU 上运行,都会观察到该行为。 Azure 支持还确认日志中没有问题。这包括打开的连接数,只有大约 50 个。我们还从其他连接进行了负载测试,服务器运行良好。
- Microsoft.Data.SqlClient 版本:我们一直在 1.1.3 版上运行,而这种行为仅在一周前 (2021-03-16) 开始。
- 网络容量:在这个阶段,我们的最大速度大约为 1-2MB/s,这是相当普通的。
- Kubernetes 扩展:事件的发生与我们扩展更多 Pod 的时间之间没有关联。
-
连接字符串问题:我们的系统过去运行良好,但无论如何我们更改了其他文章中提到的一些设置,以查看问题是否不会自行解决。火星被禁用。我们不能禁用连接池。我们将
TrusServerCertificate
设置为 true。这是当前的连接字符串:Server=tcp:***.database.windows.net,1433;Initial Catalog=***;Persist Security Info=False;User ID=***;Password=***;MultipleActiveResultSets=False;Encrypt=True;Connection Timeout=60;TrustServerCertificate=True;
更新 1: 根据要求,刚刚发生的两次超时的示例。今天是星期天,所以流量非常低。数据库利用率(CPU、内存、IO)介于 2-6% 之间。
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.SqlInternalConnection.OnError(SqlException exception,Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParserStateObject.ThrowExceptionAndWarning(Boolean callerHasConnectionLock,Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj,UInt32 error)
at Microsoft.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
at Microsoft.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
at Microsoft.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
at Microsoft.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,Boolean& dataReady)
at Microsoft.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,TdsParserStateObject stateObj)
at Microsoft.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer,TransactionManagerRequestType request,String transactionName,TransactionManagerIsolationLevel isoLevel,SqlInternalTransaction transaction,Boolean isDelegateControlRequest)
at Microsoft.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest,IsolationLevel iso,SqlInternalTransaction internalTransaction,Boolean isDelegateControlRequest)
at Microsoft.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso,Boolean shouldReconnect)
at Microsoft.Data.SqlClient.SqlConnection.BeginTransaction(IsolationLevel iso,String transactionName)
at Microsoft.Data.SqlClient.SqlConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransaction(IsolationLevel isolationLevel)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state,Func`3 operation,Func`3 verifySucceeded)
在使用此命令时,我们的数据库运行状况检查器也收到错误:Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.CanConnect()
上面的堆栈跟踪是我们正在尝试解决的问题,而不是 SQL 查询超时下面的这个堆栈跟踪。
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.SqlConnection.OnError(SqlException exception,Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,Boolean& dataReady)
at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()
at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,String resetOptionsString,Boolean isInternal,Boolean forDescribeParameterEncryption,Boolean shouldCacheForAlwaysEncrypted)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior,Boolean isAsync,Boolean inRetry,SqlDataReader ds,Boolean describeParameterEncryptionRequest)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,TaskCompletionSource`1 completion,Boolean& usedCache,String method)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
解决方法
问题是 Azure 的基础设施问题。
Azure 网络中存在一个已知问题,即 dhcp 租约是 在某些 VM 队列上发生磁盘连接/分离时丢失。有 目前正在向地区推出修复程序。我去看看什么时候 将为此发布 Azure 状态更新。
问题消失了,所以看起来修复已经在全球范围内推出了。
对于将来遇到此问题的任何其他人,您可以通过建立 SSH connection into the node(而不是 pod)来识别它。执行 ls -al /var/log/
并识别所有 syslog
文件并对每个文件运行以下 grep。
cat /var/log/syslog | grep 'carrier'
如果日志中有任何 Lost carrier
和 Gained carrier
消息,则存在某种网络问题。在我们的例子中,它是 DHCP 租约。
从我的研究来看,这个特定的超时似乎与连接超时有关,而不是与命令超时有关
我不这么认为。调用堆栈经过 System.Data.SqlClient.SqlCommand.ExecuteScalar()
,因此在成功连接后运行查询。
这是一个 CommandTimeout,由客户端放弃长时间运行的命令引起。默认的 CommandTimeout 为 30 秒。
要解决为什么命令需要很长时间,请从 Query Store 和相关的 Query Performance Insight 开始。
在 GitHub 上有一些关于此错误的噪音,但我没有看到任何证据表明除了普通的命令超时之外还有其他任何事情发生。例如,如果你跑
using (var con = new SqlConnection(constr))
{
con.Open();
var sql = @"waitfor delay '01:00:00'";
var cmd = con.CreateCommand();
//cmd.CommandTimeout = 0;
cmd.CommandText = sql;
try
{
Console.WriteLine(DateTime.Now);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(DateTime.Now);
Console.WriteLine(ex);
}
}
你会得到(使用 Microsoft.Data.SqlClient):
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): The wait operation timed out.
at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception,Boolean breakConnection,Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception,Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,Boolean callerHasConnectionLock,Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,SqlCommand cmdHandler,SqlDataReader dataStream,BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject stateObj,Boolean& dataReady)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName,Boolean isAsync,Int32 timeout,Boolean asyncWrite)
at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion,Boolean sendToPipe,Boolean& usedCache,Boolean asyncWrite,Boolean inRetry,String methodName)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at SqlClientTest.Program.Main(String[] args) in C:\Users\david\source\repos\SqlClientTest\SqlClientTest\Program.cs:line 34
或者对于 System.Data.SqlClient(您似乎正在使用)略有不同:
System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
---> System.ComponentModel.Win32Exception (258): The wait operation timed out.
--- End of inner exception stack trace ---
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception,Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception,Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName,Boolean async,Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion,String methodName)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
两者的区别
System.ComponentModel.Win32Exception (258): The wait operation timed out.
和
System.ComponentModel.Win32Exception (258): Unknown error 258
可能只是 Win32Exception 描述在 Windows 与 Linux 上的可用性。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。