entity-framework - 使用(托管)后台服务时的 .NET Core / EF Core (SQL) Max Pool 问题
问题描述
我和我的团队在高利用率的 .NET Core Web 应用程序上遇到了一些 EF Core / SQL 池问题。
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.
当托管服务 (QueuedHostedService) 的后台任务中引用 EF Core / ApplicationDbContext 时,问题开始出现。遵循以下指南:
我遵循了推荐的依赖注入和托管服务指南。
重现步骤
相关线路:
启动.cs
...
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
...
services.AddScoped<IScopedWorker, ScopedWorker>();
services.AddSingleton<MySingletonThatAddsToBackground>();
// Follow the host service guide from microsoft.
services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
MySingletonThatAddsToBackground.cs
public class MySingletonThatAddsToBackground
{
private readonly IBackgroundTaskQueue _taskQueue;
private readonly ILogger _logger;
private readonly CancellationToken _cancellationToken;
public IServiceProvider _services { get; }
public MySingletonThatAddsToBackground(IServiceProvider services, IBackgroundTaskQueue taskQueue,
ILogger<MonitorLoop> logger,
IHostApplicationLifetime applicationLifetime)
{
_services = services;
_taskQueue = taskQueue;
_logger = logger;
_cancellationToken = applicationLifetime.ApplicationStopping;
}
public void DoWorkBackground()
{
// Enqueue a background work item
_taskQueue.QueueBackgroundWorkItem(async token =>
{
try
{
using (var scope = _services.CreateScope())
{
var scopedWorker = scope.ServiceProvider.GetRequiredService<IScopedWorker>();
await scopedWorker.DoWork();
}
}
catch (OperationCanceledException)
{
// Prevent throwing if the Delay is cancelled
}
});
}
}
ScopedWorker.cs
public class ScopedWorker : IScopedWorker
{
private readonly ApplicationDbContext _db;
public ScopedWorker(ApplicationDbContext db)
{
_db = db;
}
public void DoWork()
{
var customers = _db.MyCustomers.ToListAsync();
// Do stuff to customers.
await _db.SaveChangesAsync();
}
}
讨论
在MySingletonThatAddsToBackground里面,using (var scope)
完成后,不应该释放范围,然后释放ScopedWorker
(作用域),然后释放ApplicationDbConext
(作用域),然后关闭连接/池连接吗?
是否有什么我没有正确实施导致连接池泄漏?
更多技术细节
EF Core 版本:3.1.4 数据库提供程序:Microsoft.EntityFrameworkCore.SqlServer 目标框架:.NET Core 3.1.4 操作系统:Windows Server 2016、SQL Server 2016 IDE:16.6
解决方案
我最近阅读了这篇文章(在 ASP.NET Monsters),我认为这对您的情况有所帮助:请尝试使用NETSTAT
并查看State
每个请求的监控后台服务;在文章中包含更多解释的细节,但是,在恢复时,问题与垃圾处理例程中的错误行为相关联,这会影响 HTTP 管道建立的结束。
换句话说,检查 (by NESTAT
) ifState
是否不同于ESTABLISHED
; 如果发生这种情况,您将找到根本原因,并且需要更改您的代码方法,小心使用垃圾收集。
推荐阅读
- relay - 如何在参数定义中将今天的日期作为默认值 createFragmentContainer 传递
- java - 从文件中解析Java中的JSON
- ethereum - 仲裁中的公共交易卡在交易池中待处理
- r - 订购图例标签而不是向下?
- javascript - 如何在 map 函数中重用对象?
- c# - Group By 除了实例化一个类
- javascript - 如何限制我的基于 JS 浏览器的 API 应用程序?
- r - 当其中一个选项产生 NA 时,在 R 中使用 ifelse?
- php - 将base64字符串解密为jpeg图像时损坏的图像
- mysql - 导入大型 SQL 转储时面临的问题