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

  • 时间:
  • 浏览:5
  • 来源:大发快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 ,浑然不顾数据库连接池的大小(假设是30),当填到第 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 的 实现源码 发现连接池的默认大小限制是 30

internal const int Max_Pool_Size = 30;

默认设置就会触发问题报告 ,实着随便说说的另三个白 小坑。

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

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