2

我正在使用 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。我可以看到当我通过 swagger 调用 API 时,与数据库的连接数增加到 58 个。

那我想知道:

与数据库有大约 60 个连接是否正常?然后我打算使用这个 api 连接到一个移动应用程序。

aws 上的最大连接数限制是每个移动设备或全球。我的意思是,如果两部手机连接到我的 api 并调用相同的 api 函数,它们会因为达到最大连接数而被阻止吗?

我该如何优化呢?

谢谢,

///// 编辑

我发现我有很多处于休眠状态的请求。

我怎样才能解决这个问题?我的代码如下:

builder.UseMySql(connectionString);
        //todo
        builder.EnableSensitiveDataLogging(true);
        builder.EnableDetailedErrors(true);

请在我的请求结果下方找到睡眠状态

在此处输入图像描述

4

1 回答 1

1

许多连接以睡眠状态打开的原因是,默认情况下, Pomelo 使用的MySqlConnector启用了连接池 ( Pooling=true),最大。每个连接字符串 100 个连接 ( MaxPoolSize=100)。有关所有默认设置,请参阅MySQL .NET 连接字符串选项

因此,当 60 个人并行使用应用程序 API 时,或者例如,当使用 3 个不同的连接字符串时,很容易打开大约 60 个连接,每个连接字符串有 20 个并行用户。

一旦打开了这些连接,默认情况下它们将有效地保持打开很长时间。

作为ConnectionLifeTime=0默认设置,它们永远不会被 MySqlConnector 的连接池管理显式关闭。但是,它们总是会在 MySQL 系统变量wait_timeout指定的秒数后关闭。但是由于这个变量28800默认设置为,一旦创建的池连接被 MySQL 关闭需要 8 小时(与它们处于睡眠状态的时间无关)。

因此,要减少并行连接的数量,要么禁用Pooling(如果服务器不在本地托管,则具有一些性能影响的激进方法)或通过MaxPoolSizeConnectionLifeTime连接字符串参数管理它们的生命周期。


在您提供的屏幕截图中,您可以看到主机的地址和端口有所不同,但这些是连接客户端的地址和传出端口。

但是,我上面写的也适用于这里。因此,如果您从多个 Web 服务器(从 MySQL 的角度来看是客户端)连接到您的数据库服务器,默认情况下,每个 Web 服务器将管理自己的连接池并保持最多 100 个连接打开。

例如,如果您有一个负载均衡器设置,并且其背后有多个 Web 服务器,每个服务器都可能执行数据库查询,或者您使用一些无服务器技术(如 AWS Lambda)运行您的 API,您的 API 可能托管在许多不同的 Web 服务器上,那么您最终可能会得到多个连接池(每个 Web 服务器上的每个连接字符串一个)。


我的问题是这仅适用于连接的一个用户。我Task.WhenAll()在我的应用程序中使用它并行启动多个 api 请求,并且我还在我的 api 中使用异步方法来创建一些新线程。

如果您的客户端向托管在多个 Web 服务器/AWS Lambda 上的 API 发送多个 Web 请求(例如 REST),那么 MySQL 至少需要同时打开那么多连接。

MySqlConnector 连接池将默认保持这些连接在使用后保持打开状态(每个 Web 服务器最多 100 个连接)。

您最终将获得以下数量的休眠数据库连接(假设连接字符串在每个 Web 服务器上始终保持相同):

number-of-parallel-requests-per-client * number-of-clients * number-of-webservers

然而,最大。保持打开的连接数(默认情况下)不会高于:

number-of-webservers * 100

因此,如果您的应用程序并行执行 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,您可能希望保留Pooling=true并设置MaxPoolSize一个值,该值number-of-parallel-requests-per-client * number-of-webservers将始终低于max_connections,但如果可能高于typical-number-of-parallel-clients * number-of-parallel-requests-per-client. 如果这不合理或不可能,请考虑设置Pooling=false或设置MaxPoolSize为不高于 的数字max_connections / number-of-webservers

如果您在 AWS Lambda 等无服务器技术上运行 API,请设置Pooling=false或设置MaxPoolSize为某个低值和ConnectionLifeTime大于零的某个低值。我只想设置Pooling=false,因为禁用连接池比有效地微调无服务器环境的连接池要容易得多。

于 2020-08-29T00:56:46.077 回答