长话短说

  上个月公司上线了一个物联网数据科学项目,我主要负责前端接受物联网事件,并提供 参数下载。

webapp 部署在Azure云上,参数使用Azure SQL Server存储。 最近从灰度测试转向全量部署之后,日志时常收到:

SQL Session超限报错。

19/12/18 20:41:18 [Error].[Microsoft.EntityFrameworkCore.Query].[][0HLS3MS83SC3K:00000004].[http://localhost/api/v1/soc-prediction-model/all].[].[GetModeParameters]
An exception occurred while iterating over the results of a query for context type 'Gridsum.SaicEnergyTracker.CarModelContext'.
Microsoft.Data.SqlClient.SqlException (0x80131904): Resource ID : 2. The session limit for the database is 300 and has been reached. See 'http://go.microsoft.com/fwlink/?LinkId=267637' for assistance.
Changed database context to 'saic-carmodel'.
Changed language setting to us_english.
at Microsoft.Data.ProviderBase.DbConnectionPool.CheckPoolBlockingPeriod(Exception e)
at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at Microsoft.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.AsyncQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()

排查

  我在Azure上使用的是 SQL Server Basic Edition(好歹也是付费版),全量发布至今,日均SQL访问次数约为10000,查询了Azure SQL的使用限制文档

一句话: 付费级别和计算资源大小决定了  Azure SQL最大会话数和请求数。要缓解,要么升级硬件资源,要么优化查询利用率。

查看使用EFCore访问SQL Server的过程,  也是官方默认用法:

  • 在依赖注入框架 注册一个自定义的 DbContext类型
  • 在 Controller 构造函数中获取 DbContext实例

这意味着每次请求都会创建一个DbContext实例, 可以想象到

主: 频繁创建和销毁DbContext 实例,影响App Service自身性能。

次:  在急缺CPU资源下,连接会话来不及释放,会话数不断累积,最终某时刻会超过Azure的会话限制数。

EFCore2.0 为DbContext引入新的注册方式, 能够透明的注册一个 DbContext实例池:

services.AddDbContextPool<CarModelContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SQL")));

- 一如既往支持lambda方式注册连接字符串

- 默认的DbContext Pool实例数量为 128

- 每次使用完DbContext不会释放对象,而是重置并回收到DBContextPool

Web程序中通过重用池中DbContext实例可增加高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点,   这也是EFCore2.0 其中一个性能亮点。

这么重要的使用方式竟然不在 Microsoft doc 默认Demo中推荐使用,真是一个坑。

修改代码重新部署之后,历经几天测试,暂时未出现最开始的SqlException异常。

验证

回过头随机验证SQL Server 有连接的会话数:

SELECT DEC.session_id, DEC.protocol_type, DEC.auth_scheme,
DES.login_name, DES.login_time
FROM sys.dm_exec_sessions AS DES
JOIN sys.dm_exec_connections AS DEC
ON DEC.session_id = DES.session_id;

总结

①  提示EFCore2.0 新推出的DbContextPool 特性, 提高App Service 性能。

②  尝试使用SQL Server 内置脚本验证当前有效连接的 会话数

--------------------------------------20191222 更新------------------------

查阅资料, DbContext 确实是EFCore连接会话的概念,EFCore2.0推出的DbContextPool 通过减少DBContext频繁实例化、销毁的成本来提高程序性能,

概念上类似 Ado.Net原生的连接池的概念(Ado.NET连接池是更重更底层的资源, 效果会更好)。

至于SQL查询吞吐量,DbContextPool 并没有很直接的证据能证明对SQL吞吐量有改善,目前的证据显示DbContextPool 因为app 性能提升,前端处理请求的吞吐量有20% 提升。

鉴于没有实际证据证明对SQL查询吞吐量有改善,本文不再将 数据库底层的改善直接归功于使用DbContextPool, 因此本文删除了上面的关联关系,但是DbContextPool 还是应该作为默认实践。

https://github.com/aspnet/EntityFrameworkCore/issues/9426

https://github.com/aspnet/EntityFrameworkCore/issues/10125

+  https://stackoverflow.com/questions/48443567/adddbcontext-or-adddbcontextpool

https://www.mssqltips.com/sqlservertip/5507/understanding-and-using-sysdmexecsessions-in-sql-server/

EFCore连接池的坑 差点晚年不保的更多相关文章

  1. 阿里Druid连接池的坑。。

    Druid的坑 当查询数据库的Clob转换为Oracle Clob类型的时候. java.lang.ClassCastException: com.alibaba.druid.proxy.jdbc.C ...

  2. 记录关于使用ADO.NET 连接池连接Oracle时Session信息不更新的坑

    最近的一个项目中,由于界面查询的数据量比较大,关联的表比较多,有些数据查出来需要临时保存起来供后面的查询使用,于是想到了用oracle的临时表来实现这个需求.大家都知道,oracle的临时表有两种:事 ...

  3. weblogic连接池过小导致TPS呈周期性跳坑现象

    利用晚上时间跑个12小时稳定性,第二天发现TPS曲线图成了这个样子. 排查步骤: 1.观察TPS图发现,几乎每两个小时TPS掉一次坑,是周期性的,而且TPS有掉到0的现象.LR上也有失败的交易,猜想是 ...

  4. DB数据源之SpringBoot+MyBatis踏坑过程(四)没有使用连接池的后果

    DB数据源之SpringBoot+MyBatis踏坑过程(四)没有使用连接池的后果 liuyuhang原创,未经允许禁止转载  系列目录连接 DB数据源之SpringBoot+Mybatis踏坑过程实 ...

  5. DB数据源之SpringBoot+MyBatis踏坑过程(五)手动使用Hikari连接池

    DB数据源之SpringBoot+MyBatis踏坑过程(五)手动使用Hikari连接池 liuyuhang原创,未经允许禁止转载  系列目录连接 DB数据源之SpringBoot+Mybatis踏坑 ...

  6. DB数据源之SpringBoot+MyBatis踏坑过程(七)手动使用Tomcat连接池

    DB数据源之SpringBoot+MyBatis踏坑过程(七)手动使用Tomcat连接池 liuyuhang原创,未经允许禁止转载  系列目录连接 DB数据源之SpringBoot+Mybatis踏坑 ...

  7. Druid连接池默认配置和坑

    一.公司默认配置 ds_0: !!com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: ...

  8. 关于PHP连接池扩展php-cp遇到的那些坑

    php-cp是国内大神写的php第三方扩展,具体就不用多说了,细读https://github.com/swoole/php-cp,下面来说说今天安装方法. 环境:CentOS7.2.1511 由于本 ...

  9. java连数据库和数据库连接池踩坑日记(一)-------oracle连接的一些问题

    最近接触oracle有点多,同时也在配置数据库连接池,坑也就踩多了,记录下. 事情还没有结束,没时间记录问题,很多事情都忘了,过了国庆再写的话可能就真的全忘了吧……而且不单单是数据库问题,还有一些数据 ...

随机推荐

  1. java.lang.String 的 + 号操作到底做了什么事情?

    前言  在之前的面试经历中,对于String的考察还是挺频繁的,大致考察以下几个知识点: String 常量池 new String() == 和 equals 的区别 native 方法 Strin ...

  2. MySQL 、PDO对象

    目录 1, singleton 2, pdo与db 3, singleton获取pdo 4, pdo实现db增删改查 5, pdo异常处理exception 6, pdo预处理prepare 7, p ...

  3. JavaScript笔记四

    1.运算符 逻辑运算符 ! - 非运算可以对一个布尔值进行取反,true变false false边true - 当对非布尔值使用!时,会先将其转换为布尔值然后再取反 - 我们可以利用!来将其他的数据类 ...

  4. SpringBoot系列之集成Thymeleaf用法手册

    目录 1.模板引擎 2.Thymeleaf简介 2.1).Thymeleaf定义 2.2).适用模板 3.重要知识点 3.1).th:text和th:utext 3.2).标准表达式 3.3).Thy ...

  5. nginx(二):基本应用

    配置文件详解 event段配置 worker_connections #; 每个worker进程所能够响应的最大并发请求数量: nginx最大并发响应数=worker_proceses * worke ...

  6. JRE JDK JVM的区别

    jdk>jre>jvm jdk是面向开发者具有编译功能: jre是面向用户的,主要是class文件的运行,假如我们只有编译好的class文件和jre,那么就可以运行class了. jvm是 ...

  7. sqlserver2008 R2 安装以后没有 sql server profiler

    一些人在安装好SQL server 2008 r2或者从empress升级到enterprise或者开发版之后没有SQL server profiler功能,如果需要加装则应该找到自己的安装文件(部分 ...

  8. python数据分析三个重要方法之:numpy和pandas

    关于数据分析的组件之一:numpy ndarray的属性     4个必记参数:ndim:维度shape:形状(各维度的长度)size:总长度dtype:元素类型   一:np.array()产生n维 ...

  9. 史上最强Java NIO入门:担心从入门到放弃的,请读这篇!

    本文原题“<NIO 入门>,作者为“Gregory M. Travis”,他是<JDK 1.4 Tutorial>等书籍的作者. 1.引言 Java NIO是Java 1.4版 ...

  10. JS使用readAsDataURL读取图像文件

    JS使用readAsDataURL读取图像文件 FileReader对象的readAsDataURL方法可以将读取到的文件编码成Data URL.Data URL是一项特殊的技术,可以将资料(例如图片 ...