c# - Entity Framework Core 在 sleep 状态下留下许多连接

标签 c# entity-framework asp.net-core kubernetes entity-framework-core

我有一个使用 Entity Framework Core 的 .net 核心 API。数据库上下文在 startup.cs 中注册如下:

  services.AddDbContext<AppDBContext>(options =>
         options.UseSqlServer(connectionString,
         providerOptions => providerOptions.CommandTimeout(60))); 
在我设置的连接字符串中
  Pooling=true;Max Pool Size=100;Connection Timeout=300
Controller 调用服务中的方法,服务又调用存储库中的 aysnc 方法以进行数据检索和处理。
如果在负载测试期间并发用户数低于 500,则一切正常。然而,超过这个数字,我开始看到很多超时过期错误。当我检查数据库时,没有死锁,但我可以看到超过 100 个处于 sleep 模式的连接(API 托管在两个 kubernetes pod 上)。我在测试过程中监控了这些连接,看起来不是重用当前的 sleep 连接,而是将新的连接添加到池中。我的理解是 Entity Framework 核心管理打开和关闭连接,但情况似乎并非如此。还是我错过了什么?

The error looks like this:

StatusCode":500,"Message":"Error:Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. Stack Trace:



Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)\n



Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource1 retry, DbConnectionOptions userOptions)\n at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource1 retry, SqlConnectionOverrides overrides)\n at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)\n


在 Microsoft.Data.SqlClient.SqlConnection.Open()\n 在

Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(Boolean errorsExpected)\n



Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)\n at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransaction(IsolationLevel isolationLevel)\n.....................

dbcontext 的一个例子被使用:
Controller 调用服务类中的方法:
  var result = await _myservice.SaveUserStatusAsync(userId, status);
然后在 'myservice' :
  var user = await _userRepo.GetUserAsync(userId);

  ....set user status to new value and then

  return await _userRepo.UpdateUserAsync(user);
然后在 'userrepo' :
  _context.user.Update(user);
   var updated = await _context.SaveChangesAsync();
   return updated > 0;
更新:
非常感谢 Ivan Yang 慷慨地提供了赏金。尽管我仍在调查中,但通过阅读下面的所有评论和答案,我学到了很多东西。这是我迄今为止尝试过的:我将池大小增加到 200(我知道这不是解决问题的正确方法),增加了 Pod 的数量,以便 API 现在在 4 个 Pod 上运行并分配更多内存到每个 pod 。到目前为止的最终结果是好的:500 个错误在多达 2000 个并发用户的情况下完全消失。在尝试其他选项后,我将用我的发现更新这个问题。

最佳答案

Error:Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.


这几乎总是连接泄漏。在这里,您的查询运行时间很短,并且您在服务器上看到空闲连接这一事实证实了这一点。在某个地方你要离开一个开放的连接。
DbContext 将打开/关闭底层连接,并在 Dispose 上将其返回到池中。但是如果你在一个连接上启动一个事务并且没有提交或回滚,这个连接将被隔离在池中并且不会被重用。或者,如果您返回 IEnumerableDataReader永远不会被迭代和处理,连接不能被重用。
查看“休眠” session 以查看它们的最后一个查询是什么,并将其与您的代码进行交叉引用以追踪泄漏连接的调用站点。首先尝试 DMV,例如
select s.session_id, s.open_transaction_count, ib.event_info
from sys.dm_exec_sessions s
cross apply sys.dm_exec_input_buffer(s.session_id,null) ib
或在必要时启动扩展事件跟踪。

关于c# - Entity Framework Core 在 sleep 状态下留下许多连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68786746/

相关文章:

c# - ExecuteNonQuery 在 C# 中不起作用

c# - 通过查询字符串将复杂对象传递到 .netcore1.1 Webapi

asp.net-core - VS 2017 15.3 中的 SignalR Core w/ASP.net Core 2.0 无法加载文件或程序集“System.Diagnostics.DiagnosticSource,版本=4.0.2.1”

c# - 即使值为 null,StringValues 计数也显示 1

asp.net - 使用 Entity Framework 创建具有多个查询的 MVC ViewModel

linq - Entity Framework LINQ 查询开始超时 - 数据库服务器重启后再次加速

c# - 返回字符串或重定向到另一个 Controller 的方法

c# - 'DisplayBox_TextChanged'没有定义

c# - 在 C# 中构建(转义)JavaScript 正则表达式

c# - 使用带有泛型类的 ContextBuilder 使用 Entity Framework 4 创建 EDMX/DB-Schema 的异常