问题描述
我正在使用aspnetboilerplate核心和entityframework核心。
我有1个很大的请求实体框架核心:
var user = _userRepository.GetAll()
.Include(u => u.FavoriteMeals).ThenInclude(c => c.Category)
.Include(u => u.FavoriteRestaurants).ThenInclude(c => c.CategoryMaster)
.Include(u => u.FavoriteSpecialityMeals).ThenInclude(c => c.Speciality)
.Include(u => u.FavoriteSuperBookings).ThenInclude(c => c.Boooking)
.Include(u => u.FavouritePlaces).ThenInclude(c => c.Place)
.Include(u => u.Followers).ThenInclude(u => u.User1)
.Include(u => u.Followings).ThenInclude(u => u.User2)
.FirstOrDefault(r => r.Id == id);
我使用AWS RDS MysqL。而且我看到当我用招摇的方式调用API时,与数据库的连接数已增加到58。
那我想知道:
与数据库建立约60条连接是否正常?然后,我计划使用此api连接到移动应用程序。
aws上的最大连接数限制是每个移动设备或全局。我的意思是,如果两个手机都连接到我的api并调用相同的api函数,它们会因为达到最大连接数而被阻止吗?
如何优化呢?
谢谢
/////编辑
我发现我有很多请求处于休眠状态。
builder.UseMysqL(connectionString);
//todo
builder.EnableSensitiveDataLogging(true);
builder.EnableDetailedErrors(true);
请在我的请求结果下方找到睡眠状态
解决方法
许多连接以睡眠状态打开的原因是,默认情况下,Pomelo使用的MySqlConnector启用了连接池(Pooling=true
),最大值为。每个连接字符串(MaxPoolSize=100
)最多100个连接。有关所有默认设置,请参见MySQL .NET Connection String Options。
因此,当60个人并行使用app API时,例如当使用3个不同的连接字符串时,每个字符串并行包含20个用户。
一旦这些连接被打开,默认情况下,它们将有效地长时间保持打开状态。
使用ConnectionLifeTime=0
作为默认设置,它们将永远不会被MySqlConnector的连接池管理显式关闭。但是,它们总是在MySQL系统变量wait_timeout指定的秒数后关闭。但是,由于默认情况下此变量设置为28800
,因此一旦MySQL创建的池化连接被关闭(与它们处于睡眠状态的时间无关),将需要8个小时。
因此,要减少并行连接的数量,请禁用Pooling
(如果服务器不是本地托管的,则是自由基方法,可能会影响性能),或者通过MaxPoolSize
和{{1 }}连接字符串参数。
在提供的屏幕截图中,您可以看到主机的地址和端口有所不同,但这是连接客户端的地址和传出端口。
但是,我上面写的内容在这里也适用。因此,如果您要从多个Web服务器(从MySQL的角度来看是客户端)连接到数据库服务器,则默认情况下,每个Web服务器将管理自己的连接池并保持多达100个连接打开。
例如,如果您有一个负载平衡器设置,并且其后有多个Web服务器可以分别执行数据库查询,或者您使用一些无服务器技术(例如AWS Lambda)运行API,则该API可以托管在许多服务器上不同的Web服务器,则最终可能会有多个连接池(每个Web服务器上的每个连接字符串一个)。
我的问题是仅适用于一个已连接的用户。我在我的应用程序中使用
ConnectionLifeTime
,它会并行启动多个api请求,并且在我的api中也使用异步方法,这会创建一些新线程。
如果您的客户端向托管在多个Web服务器/ AWS Lambda上的API发送多个Web请求(例如REST),则MySQL至少需要同时打开多个连接。
使用完MySqlConnector连接池后,默认情况下这些连接将保持打开状态(每个Web服务器最多100个连接)。
您最终将获得以下数量的睡眠数据库连接(假设每个Web服务器上的连接字符串始终保持不变):
Task.WhenAll()
但是,最大保持打开状态的连接数(默认情况下)不大于:
number-of-parallel-requests-per-client * number-of-clients * number-of-webservers
因此,如果您的应用并行执行20个请求,并且每个请求都建立了从API(Web服务器)到数据库服务器的数据库连接,那么根据您的API托管方案,将发生以下情况:
-
3台带有负载均衡器的Web服务器::如果您足够频繁地运行应用程序,则负载均衡器将随着时间的流逝将请求分发给所有3台Web服务器。因此,这3个Web服务器中的每一个将保持大约20个与数据库服务器的连接。只要只有一个客户端同时执行这些请求,您就可以建立60个连接。如果最大4个客户端并行运行20个请求,随着时间的推移,每个Web服务器将保持80个连接保持打开状态,因此总共3 * 80 = 240个睡眠数据库连接。
-
无服务器技术,例如AWS Lambda::与上一个示例相同,适用于AWS Lambda,但是Web服务器的数量是无限的(理论上)。因此,如果AWS决定将API调用分发到许多不同的Web服务器,那么您可能很快就会超过MySQL的max_connections设置。
建议如何配置连接池
如果您在固定数量的Web服务器上运行API,则可能需要保留number-of-webservers * 100
并将Pooling=true
设置为一个值,MaxPoolSize
将始终小于{{ 3}},但如果可能的话请高于number-of-parallel-requests-per-client * number-of-webservers
。如果这不合理或不可能,请考虑将typical-number-of-parallel-clients * number-of-parallel-requests-per-client
设置为1或将Pooling=false
设置为不高于MaxPoolSize
的数字。
如果您在诸如AWS Lambda之类的无服务器技术上运行API,请设置max_connections / number-of-webservers
或将Pooling=false
设置为某个低值,并将MaxPoolSize
设置为某个大于零的低值。我只设置ConnectionLifeTime
,因为禁用连接池要比针对无服务器环境有效地微调连接池要容易得多。