使用DbContextPool提高EfCore查询性能
長(zhǎng)話短說(shuō)
上個(gè)月公司上線了一個(gè)物聯(lián)網(wǎng)數(shù)據(jù)科學(xué)項(xiàng)目,我主要負(fù)責(zé)前端接收設(shè)備Event,并提供模型參數(shù)下載(數(shù)據(jù)科學(xué)團(tuán)隊(duì)會(huì)優(yōu)化參數(shù))。WebApp部署在Azure,模型參數(shù)使用Azure SQL Server存儲(chǔ)。
最近從灰度測(cè)試轉(zhuǎn)向全量部署之后,日志中時(shí)常出現(xiàn):SQL Session會(huì)話超限的報(bào)錯(cuò)。
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(好歹也是付費(fèi)版),全量發(fā)布至今,日均SQL訪問(wèn)次數(shù)約為10000,查詢了Azure SQL的使用限制文檔:
一句話:付費(fèi)級(jí)別和計(jì)算資源大小決定了Azure SQL最大會(huì)話數(shù)/請(qǐng)求數(shù)。
若要緩解,要么升級(jí)硬件資源,要么優(yōu)化查詢利用率。
本次使用EFCore操作SQL Server的方式, 是官方默認(rèn)用法:
?依賴注入框架注冊(cè)一個(gè)自定義的 DbContext類型
?在Controller構(gòu)造函數(shù)中獲取 DbContext實(shí)例
這意味著每次請(qǐng)求都會(huì)創(chuàng)建一個(gè) DbContext實(shí)例, 可以想象到
?① 在高并發(fā)請(qǐng)求下,連接數(shù)不斷累積,最終某時(shí)刻會(huì)超過(guò) Azure 的連接限制數(shù)量。
?② 頻繁創(chuàng)建和銷毀 DbContext 實(shí)例,影響App Service自身性能。
EFCore2.0 為DbContext引入新的注冊(cè)方式:透明地注冊(cè)了 DbContext實(shí)例池:
services.AddDbContextPool<CarModelContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SQL")));? - 一如既往支持lambda方式注冊(cè)連接字符串
? - 默認(rèn)的連接池?cái)?shù)量為 128
? - 每次使用完DbContext不會(huì)釋放對(duì)象,而是重置并回收到DBContextPool
Web程序中通過(guò)重用池中DbContext實(shí)例可提高高并發(fā)場(chǎng)景下的吞吐量,?這在概念上類似于ADO.NET Provider原生的連接池操作方式,具有節(jié)省DbContext實(shí)例化成本的優(yōu)點(diǎn), 這也是EFCore2.0 其中一個(gè)性能亮點(diǎn)。
這么重要的使用方式竟然不在 EFCore Doc指南中默認(rèn)演示,真是一個(gè)坑。
修改代碼重新部署之后,歷經(jīng)幾天測(cè)試,暫時(shí)未出現(xiàn)最開(kāi)始的SqlException異常。
驗(yàn)證
回過(guò)頭隨機(jī)驗(yàn)證SQL Server會(huì)話中的有效連接數(shù)量: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;總結(jié)
①? 提示EFCore2.0新推出的DbContextPool特性,有效提高SQL查詢吞吐量
②? 嘗試使用SQL Server 內(nèi)置腳本自證會(huì)話中有效連接數(shù)
+??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
總結(jié)
以上是生活随笔為你收集整理的使用DbContextPool提高EfCore查询性能的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何构建知识体系
- 下一篇: [原]调试实战——程序CPU占用率飙升,