EF Core 小坑:DbContextPool 会引起数据库连接池连接耗尽

  • 时间:
  • 浏览:2
  • 来源:幸运快3_快3平台网址_幸运快3平台网址

DbContextPool 是 ASP.NET Core 2.1 引入的新价值形式,还要能 节省创建 DbContext 实例的开销,但非要想到其中藏着另有一个 小坑。

最近有另有一个 ASP.NET Core 项目持续运行一段时间后日志中就会出现数据库连接池达到最大连接数限制的错误:

System.InvalidOperationException: 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.
   at System.Data.Common.ADP.ExceptionWithStackTrace(Exception e)

回会但是但是结束了了以为是哪个地方的代码造成 DbContext 非要正常 Dispose ,但在代码中非要找到任何相关线索。回会实在非要或者 还要能 怀疑的地方,唯有 DbContextPool ,于是尝试加进去 DbContextPool ,结果错误就消失了。居然是 DbContextPool 引起的,但让我纳闷的是 DbContextPool 从前只是为了节省创建 DbContext 实例的开销,为什么么反而消耗更多数据库连接,为什么么让或者 项目的负载很低,为什么么机会把整个连接池都消耗殆尽呢?

今天在周会上谈了或者 怪大问题,回会一直想到:每个 DbContext 实例回会占用另有一个 数据库连接(SqlConnection),不启用 DbContextPool 的回会,请求一回会但是刚结束了了,对应 DbContext 实例就被 Dispose ,数据库连接就会被放回连接池。而使用 DbContextPool 的回会,请求回会但是刚结束了了后 DbContext 回会被 Dispose 只是被放回 DbContextPool ,DbContext 被放回属于个人的池中,就原因它对应的数据库连接回会被放回它所属的连接池。DbContextPool 中的每另有一个 DbContext 都对应另有一个 数据库连接,DbContextPool 中每多另有一个 DbContext ,数据库连接池中就会少另有一个 数据库连接。当这另有一个 池的大小不一样且 DbContextPool 大于数据库连接池,大问题就来了,DbContextPool 根据自家池(假设是128)子的大小畅快地向池中填 DbContext ,浑然不顾数据库连接池的大小(假设是3000),当填到第 101 个 DbContext 时就会出现上面的错误。

或者 项目中用的回会默认设置,是回会默认设置就会触发或者 大问题呢?

查看 DbContextPool 的 实现源码 发现池的默认大小限制是 128

public static IServiceCollection AddDbContextPool<TContext>(
    [NotNull] this IServiceCollection serviceCollection,
    [NotNull] Action<DbContextOptionsBuilder> optionsAction,
    int poolSize = 128)
    where TContext : DbContext
    => AddDbContextPool<TContext, TContext>(serviceCollection, optionsAction, poolSize);

查看 SqlConnention 的 实现源码 发现连接池的默认大小限制是 3000

internal const int Max_Pool_Size = 3000;

默认设置就会触发大问题,实实在在的另有一个 小坑。

知道了原因,补救起来就很简单了,将 DbContextPool 的 poolSize 设置为小于数据库连接池的 Max_Pool_Size

services.AddDbContextPool<JobDb>(option =>
    option.UseSqlServer(Configuration.DbConnectionStr()), 
    poolSize: 64);