【问题标题】:SocketException (995) with EF Core and Pomelo带有 EF Core 和 Pomelo 的 SocketException (995)
【发布时间】:2021-11-10 02:06:34
【问题描述】:

我的应用程序有时会抛出此异常:
MySqlConnector.MySqlException (0x80004005): Connect Timeout expired. All pooled connections are in use.

我从托管服务提供商处发现,我的应用程序的 mysql 中有很多空闲连接。

因此我尝试通过在连接字符串中添加POOLING=FALSE 来禁用池。相反,我得到了以下异常。

 ---> MySqlConnector.MySqlException (0x80004005): The Command Timeout expired before the operation completed.
 ---> System.IO.IOException: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..
 ---> System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.
   --- End of inner exception stack trace ---
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.GetResult(Int16 token)
   at System.Net.Security.SslStream.<FillBufferAsync>g__InternalFillBufferAsync|215_0[TReadAdapter](TReadAdapter adap, ValueTask`1 task, Int32 min, Int32 initial)
   at System.Net.Security.SslStream.ReadAsyncInternal[TReadAdapter](TReadAdapter adapter, Memory`1 buffer)
   at MySqlConnector.Protocol.Serialization.StreamByteHandler.<ReadBytesAsync>g__DoReadBytesAsync|6_2(Memory`1 buffer) in /_/src/MySqlConnector/Protocol/Serialization/StreamByteHandler.cs:line 89
   at MySqlConnector.Protocol.Serialization.StreamByteHandler.<ReadBytesAsync>g__DoReadBytesAsync|6_2(Memory`1 buffer) in /_/src/MySqlConnector/Protocol/Serialization/StreamByteHandler.cs:line 89
   at MySqlConnector.Protocol.Serialization.BufferedByteReader.ReadBytesAsync(IByteHandler byteHandler, ArraySegment`1 buffer, Int32 totalBytesToRead, IOBehavior ioBehavior) in /_/src/MySqlConnector/Protocol/Serialization/BufferedByteReader.cs:line 36
   at MySqlConnector.Protocol.Serialization.ProtocolUtility.<ReadPacketAsync>g__AddContinuation|1_0(ValueTask`1 headerBytes, BufferedByteReader bufferedByteReader, IByteHandler byteHandler, Func`1 getNextSequenceNumber, ProtocolErrorBehavior protocolErrorBehavior, IOBehavior ioBehavior) in /_/src/MySqlConnector/Protocol/Serialization/ProtocolUtility.cs:line 412
   at MySqlConnector.Protocol.Serialization.ProtocolUtility.<DoReadPayloadAsync>g__AddContinuation|5_0(ValueTask`1 readPacketTask, BufferedByteReader bufferedByteReader, IByteHandler byteHandler, Func`1 getNextSequenceNumber, ArraySegmentHolder`1 previousPayloads, ProtocolErrorBehavior protocolErrorBehavior, IOBehavior ioBehavior) in /_/src/MySqlConnector/Protocol/Serialization/ProtocolUtility.cs:line 483
   at MySqlConnector.Core.ServerSession.ReceiveReplyAsyncAwaited(ValueTask`1 task) in /_/src/MySqlConnector/Core/ServerSession.cs:line 890
   at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in /_/src/MySqlConnector/Core/ResultSet.cs:line 50
   at MySqlConnector.MySqlDataReader.ActivateResultSet(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 119
   at MySqlConnector.MySqlDataReader.CreateAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, IDictionary`2 cachedProcedures, IMySqlCommand command, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 445
   at MySqlConnector.Core.CommandExecutor.ExecuteReaderAsync(IReadOnlyList`1 commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/CommandExecutor.cs:line 60
   at MySqlConnector.MySqlCommand.ExecuteReaderAsync(CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlCommand.cs:line 315
   at MySqlConnector.MySqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlCommand.cs:line 307
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9.GetRolesAsync(TUser user, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Identity.UserManager`1.GetRolesAsync(TUser user)
   at Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory`2.GenerateClaimsAsync(TUser user)
   at Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory`1.CreateAsync(TUser user)
   at Microsoft.AspNetCore.Identity.SignInManager`1.CreateUserPrincipalAsync(TUser user)
   at Microsoft.AspNetCore.Identity.SecurityStampValidator`1.SecurityStampVerified(TUser user, CookieValidatePrincipalContext context)
   at Microsoft.AspNetCore.Identity.SecurityStampValidator`1.ValidateAsync(CookieValidatePrincipalContext context)
   at Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context)

我想知道是什么导致了这个异常,以及处理空闲 mysql 连接问题的更好方法是什么。

【问题讨论】:

    标签: c# asp.net-core ef-core-3.1 pomelo-entityframeworkcore-mysql


    【解决方案1】:

    因此我尝试通过在连接字符串中添加POOLING=FALSE 来禁用池。相反,我得到了以下异常。

    您得到---&gt; MySqlConnector.MySqlException (0x80004005): The Command Timeout expired before the operation completed. 异常的原因很可能是最大值。您的 MySQL 实例的连接已经耗尽。

    如果您不想重新配置 MySQL 实例,让您的应用运行的最简单方法是禁用连接池(就像您已经做过的那样),然后重新启动服务器(以确保没有来自您的旧代码阻止您连接)。


    如果你毕竟想使用连接池,你可能还想看看 MySqlConnector 的Connection Pooling Options

    它们包含用于管理连接池的连接数量及其生命周期的选项(默认数量为100,默认生命周期为无限)。

    特别要仔细看看MaxPoolSizeConnectionIdleTimeout

    另外,请确保您的连接字符串不会更改。 MySqlConnector(以及 Pomelo)为每个唯一的连接字符串使用一个专用的连接池。


    除此之外,在 MySQL 数据库级别,您可以使用 wait_timeout 选项强制在特定超时后关闭连接。

    它的默认值通常是28800(8 小时)。

    【讨论】:

    • 限制MaxPoolSize的数量有什么缺点吗?
    • 如果您创建的连接数多于MaxPoolSize,那么这些多余的连接将在您完成后关闭而不是返回到池中。因此,如果MaxPoolSize 非常小,则并非所有连接都可以从池中受益。但是,如果您的数据库是本地的(与应用程序相同的机器或网络),那么对于大多数应用程序来说,不进行池化的开销可以忽略不计。您应该确保使用同一 MySQL 实例的所有应用程序的所有连接池的 MaxPoolSize 值的总和低于该 MySQL 实例的 max_connections 值。
    • 明白。就我而言,我使用的是共享托管服务,我不确定数据库是否与我的应用程序托管在同一台服务器上。但是我的托管服务提供商抱怨我的应用程序有很多空闲的 MySQL 连接,所以我需要减少 MaxPoolSize 的数量。
    • 顺便说一句,您使用的是哪个版本的 Pomelo 和 MySqlConnector?
    • 我正在使用这个 nuget 包&lt;PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.0" /&gt;。以前我使用的是 5.0.1
    【解决方案2】:

    1.Connection Timeout=300(以秒为单位的时间)

    2.默认命令超时=300(时间以秒为单位)

    像这样使用你的连接:-

    "ConnectionStrings": {  
        "DefaultConnection": "server=localhost; port=3306; database=dbname; user=username; password=yourpassword; Persist Security Info=False; Connect Timeout=300;default command timeout=300"  
      } 
    

    或者

    "server=yourservername;userid=xxxxx;password=xxxxx;database=xxxxx;Connection Timeout=300;default command timeout=300"
    

    或者你可以定义 Time out on Startup 类如下:-

    services.AddDbContext<YourDbContextName>(options =>
                    options.UseMySql(
                        Configuration.GetConnectionString("DefaultConnection"), o => o.CommandTimeout(180)));
    
    

    它将解决您的问题。

    【讨论】:

    • 请问这是否解决了空闲连接问题或 IO 已中止问题?
    • @RyanTeh 也许是连接问题。因为您的命令超时已过期,您才发现此问题。我只是为我的答案声明一个时间范围,它会起作用。
    • 似乎是连接超时问题。我将托管服务提供商提供的连接字符串复制并粘贴到我的配置文件中,并且在此之前从未真正正确地查看过它。我查看了连接字符串,在托管服务提供商提供的连接字符串中,连接超时设置为 60。也许这就是连接超时的原因。我已经尝试了您的建议,并将再监控几天。
    猜你喜欢
    • 2022-07-26
    • 2018-11-22
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 2020-11-27
    • 2020-11-27
    • 1970-01-01
    相关资源
    最近更新 更多