【发布时间】:2014-03-13 08:00:25
【问题描述】:
我们最近开发了一个基于 SOA 的站点,但是该站点在负载过重时最终会出现严重的负载和性能问题。我在这里发布了一个与此问题相关的问题:
ASP.NET website becomes unresponsive under load
该站点由托管在 4 节点集群上的 API(WEB API)站点和托管在另一个 4 节点集群上并调用 API 的网站组成。两者都是使用 ASP.NET MVC 5 开发的,所有操作/方法都基于 async-await 方法。
在 NewRelic 等一些监控工具下运行该站点,调查几个转储文件并分析工作进程后,事实证明,在非常轻的负载(例如 16 个并发用户)下,我们最终拥有大约 900 个线程,其中使用了 100 个% 的 CPU 并填满了 IIS 线程队列!
尽管我们通过引入大量缓存和性能修正来设法将站点部署到生产环境,但我们团队中的许多开发人员认为我们必须删除所有异步方法并将 API 和网站转换为普通 Web API 和简单地返回一个动作结果的动作方法。
我个人对这种方法不满意,因为我的直觉是我们没有正确使用异步方法,否则这意味着微软引入了一个基本上具有破坏性且无法使用的功能!
您是否知道任何参考资料清楚说明应该/可以在何处以及如何使用异步方法?我们应该如何使用它们来避免这样的戏剧?例如根据我在 MSDN 上阅读的内容,我认为 API 层应该是异步的,但该网站可能是一个普通的非异步 ASP.NET MVC 站点。
更新:
这是与 API 进行所有通信的异步方法。
public static async Task<T> GetApiResponse<T>(object parameters, string action, CancellationToken ctk)
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(BaseApiAddress);
var formatter = new JsonMediaTypeFormatter();
return
await
httpClient.PostAsJsonAsync(action, parameters, ctk)
.ContinueWith(x => x.Result.Content.ReadAsAsync<T>(new[] { formatter }).Result, ctk);
}
}
这种方法有什么愚蠢的吗?请注意,当我们将所有方法转换为非异步方法时,我们获得了更好的性能。
这是一个示例用法(我已经删除了与验证、日志记录等相关的代码的其他部分。此代码是 MVC 操作方法的主体)。
在我们的服务包装器中:
public async static Task<IList<DownloadType>> GetSupportedContentTypes()
{
string userAgent = Request.UserAgent;
var parameters = new { Util.AppKey, Util.StoreId, QueryParameters = new { UserAgent = userAgent } };
var taskResponse = await Util.GetApiResponse<ApiResponse<SearchResponse<ProductItem>>>(
parameters,
"api/Content/ContentTypeSummary",
default(CancellationToken));
return task.Data.Groups.Select(x => x.DownloadType()).ToList();
}
在行动中:
public async Task<ActionResult> DownloadTypes()
{
IList<DownloadType> supportedTypes = await ContentService.GetSupportedContentTypes();
【问题讨论】:
-
应用程序如何使用 async/await 的任何示例?当与 IO 绑定操作(如数据库调用和文件操作)一起使用时,它通常应该增加可伸缩性,而不是降低它。如果它产生了不必要的线程,以便每个方法都可以标记为异步,那可能是一个危险信号,并且可能是您的问题的原因。
-
也许,您的代码使用
Task.Run包装了同步API,而不是使用自然的异步API? stackoverflow.com/q/21690385/1768303。一般来说,在服务器上使用Task.Run是个坏主意。 -
是 MVC 5 吗?还是您的标签所说的 MVC 3?
-
@ErikTheViking 抱歉我修改了标签。
-
@AnthonyChu,WEB 和 API(消费者和服务)中的几乎所有方法和操作方法都是异步的!今天我也创建了一个完全同步的版本,并将它们置于负载测试之下。令人惊讶的是,如果我直接点击 API,API 的异步版本比同步版本更快。但是当我使用 Apache 基准测试工具访问网站时,API 的异步版本慢了三倍!您认为仅将与 DB 或 ElasticSearch 通信的方法转换为异步方法更好吗?正如 Noseratio 所说,使用自然异步 API?
标签: performance asp.net-mvc-4 async-await