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

  • 时间:
  • 浏览:2
  • 来源:大发快三_快三苹果app下载_大发快三苹果app下载

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 ,浑然不顾数据库连接池的大小(假设是50),当填到第 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 的 实现源码 发现连接池的默认大小限制是 50

internal const int Max_Pool_Size = 50;

默认设置就会触发问題,实觉得在的有一个小坑。

知道了由于,避免起来就很简单了,将 DbContextPool 的 poolSize 设置为小于数据库连接池的 Max_Pool_Size

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