使用DbContextPool提高EfCore查询性能
長話短說
上個月公司上線了一個物聯網數據科學項目,我主要負責前端接收設備Event,并提供模型參數下載(數據科學團隊會優化參數)。WebApp部署在Azure,模型參數使用Azure SQL Server存儲。
最近從灰度測試轉向全量部署之后,日志中時常出現:SQL Session會話超限的報錯。
19/12/18 20:41:18 [Error].[Microsoft.EntityFrameworkCore.Query].[][0HLS3MS83SC3K:00000004].[http://******/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實例, 可以想象到
?① 在高并發請求下,連接數不斷累積,最終某時刻會超過 Azure 的連接限制數量。
?② 頻繁創建和銷毀 DbContext 實例,影響App Service自身性能。
EFCore2.0 為DbContext引入新的注冊方式:透明地注冊了 DbContext實例池:
services.AddDbContextPool<CarModelContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SQL")));? - 一如既往支持lambda方式注冊連接字符串
? - 默認的連接池數量為 128
? - 每次使用完DbContext不會釋放對象,而是重置并回收到DBContextPool
Web程序中通過重用池中DbContext實例可提高高并發場景下的吞吐量,?這在概念上類似于ADO.NET Provider原生的連接池操作方式,具有節省DbContext實例化成本的優點, 這也是EFCore2.0 其中一個性能亮點。
這么重要的使用方式竟然不在 EFCore Doc指南中默認演示,真是一個坑。
修改代碼重新部署之后,歷經幾天測試,暫時未出現最開始的SqlException異常。
驗證
回過頭隨機驗證SQL Server會話中的有效連接數量:48
SELECT DEC.session_id, DEC.protocol_type, DEC.auth_scheme,DES.login_name, DES.login_time FROM sys.dm_exec_sessions AS DESJOIN sys.dm_exec_connections AS DECON DEC.session_id = DES.session_id;總結
①? 提示EFCore2.0新推出的DbContextPool特性,有效提高SQL查詢吞吐量
②? 嘗試使用SQL Server 內置腳本自證會話中有效連接數
+??https://stackoverflow.com/questions/48443567/adddbcontext-or-adddbcontextpool
+?https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.0#dbcontext-pooling
總結
以上是生活随笔為你收集整理的使用DbContextPool提高EfCore查询性能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何构建知识体系
- 下一篇: [原]调试实战——程序CPU占用率飙升,