ASP.NET Core 2.2 kestrel 服务器的性能问题

ASP.NET Core 2.2 kestrel server's performance issue

我遇到了 kestrel 服务器的性能问题。我有以下场景:

    TestClient(JMeter) -> DemoAPI-1(Kestrel) -> DemoAPI-2(IIS) 

我正在尝试创建一个示例应用程序,它可以在请求时获取文件内容。 TestClient(100 Threads) 请求 DemoAPI-1,DemoAPI-1 又请求 DemoAPI-2。 DemoAPI-2 读取一个固定的 XML 文件(最大 1 MB)并且 returns 它的内容作为响应(在生产中 DemoAPI-2 不会被暴露到外面的世界)。

当我测试从 TestClient -> DemoAPI-2 的直接访问时,我得到了以下预期结果(良好):

  1. 平均:368 毫秒
  2. 最小值:40 毫秒
  3. 最大:1056 毫秒
  4. 吞吐量:40.1/秒

但是当我尝试通过 DemoAPI-1 访问它时,我得到了以下结果:

  1. 平均:48232 毫秒
  2. 最小值:21095 毫秒
  3. 最大值:49377 毫秒
  4. 吞吐量:2.0/秒

如您所见,有一个巨大的 difference.I 甚至没有获得 DemoAPI-2 的 10% 吞吐量。有人告诉我,与传统的 IIS 相比,kestrel 更高效、更快速。也因为直接访问没有问题,我想我们可以排除DemoAPI-2.

上出现问题的可能

※演示代码API-1 :

string base64Encoded = null;
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var response = await this.httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead).ConfigureAwait(false);

            if (response.StatusCode.Equals(HttpStatusCode.OK))
            {
                var content = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
                base64Encoded = Convert.ToBase64String(content);
            }
return base64Encoded;

※演示代码API-2 :

[HttpGet("Demo2")]
    public async Task<IActionResult> Demo2Async(int wait)
    {
        try
        {
            if (wait > 0)
            {
                await Task.Delay(wait);
            }
            var path = Path.Combine(Directory.GetCurrentDirectory(), "test.xml");
            var file = System.IO.File.ReadAllText(path);
            return Content(file);
        }
        catch (System.Exception ex)
        {
            return StatusCode(500, ex.Message);
        }
    }

一些附加信息:

  1. 两个 API 都是异步的。
  2. 两个 API 都托管在不同的 EC2 实例上(C5.xlarge Windows Server 2016)。
  3. DemoAPI-1(kestrel) 是一个独立的API(没有反向代理)
  4. 为此测试将 TestClient(jMeter) 设置为 100 个线程。
  5. 目前还没有对 kestrel 服务器进行其他配置。
  6. 目前还没有可能影响性能的操作过滤器、中间件或日志记录。
  7. 通信是在 5001 端口上使用 SSL 完成的。
  8. 演示的等待参数API2 目前设置为 0。
  9. DEMOAPI-1的CPU使用率不超过40%。

DEMOAPI-1 执行 non-asynchronous 流读取:

var bytes = stream.Read(read, 0, DataChunkSize);

while (bytes > 0)
{
  buffer += System.Text.Encoding.UTF8.GetString(read, 0, bytes);
  // Replace with ReadAsync
  bytes = stream.Read(read, 0, DataChunkSize);
}

这可能是很多请求的吞吐量问题。

此外,我不完全明白您为什么不使用 IIS 和 Kestrel 测试相同的代码,我认为您只需要更改环境而不是代码。

问题是由于HttpClient 的端口耗尽问题。 我能够通过使用 IHttpClientFactory 来解决这个问题。 以下文章可能会对遇到类似问题的人有所帮助。

https://www.stevejgordon.co.uk/httpclient-creation-and-disposal-internals-should-i-dispose-of-httpclient