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

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

internal const int Max_Pool_Size = 400;

默认设置就会触发大问提,实我我随便说说在的有两个 小坑。

知道了原困,正确处理起来就很简单了,将 DbContextPool 的 poolSize 设置为小于数据库连接池的 Max_Pool_Size

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