簡體   English   中英

在 Asp.Net Core 的 https 上下文中調用 HttpClient 時速度很慢

[英]HttpClient is slow when called in an https context in Asp.Net Core

我有一台使用 Asp.Net Core 的服務器,但在使用 HTTPS 時遇到了延遲問題。 當只獲取幾張圖片時,每個請求大約需要 20 毫秒來處理。 但是,當我同時發出 125 個請求時,使用 HTTP 時它們會減慢到 30-80 毫秒(可接受),而使用 HTTPS 時會減慢到 130-850 毫秒(不可接受)。

我已經進行了一些調試,當我的服務器對 WMS 服務器進行 http 調用時會出現減速。

添加自定義套接字處理程序將延遲從 4000-6000 毫秒減少到當前的 130-850 毫秒,因此幫助很大,但延遲仍然有點多。

PS:服務器將做的不僅僅是代理查詢,所以我不能簡單地為該角色使用專用代理服務器。

這是服務器代碼的最小示例:

using System.Diagnostics.Tracing;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;

using var socketHandler = new SocketsHttpHandler()
{
    PooledConnectionIdleTimeout = TimeSpan.FromMinutes(10),
    PooledConnectionLifetime = TimeSpan.FromMinutes(10),
    MaxConnectionsPerServer = 1,
};

using var httpClient = new HttpClient(socketHandler);

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSingleton(httpClient);

var app = builder.Build();
app.MapControllers();
app.Run();


[ApiController]
[Route("[controller]")]
public class WMSController : ControllerBase
{
    private readonly HttpClient Client;
    private readonly string BaseUrl;

    public WMSController(HttpClient client)
    {
        Client = client;
        BaseUrl = "http://my-local-hostname.company.internal:10301/WMS";
    }

    [HttpGet(Name = "WMS")]
    public async Task<ActionResult> GetWms()
    {
        var query = HttpContext.Request.QueryString.Value;

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var response = await Client.GetAsync(BaseUrl + query); // This is the slow part.
        stopwatch.Stop();

        Console.WriteLine($"{DateTime.Now:HH:mm:ss} - {stopwatch.ElapsedMilliseconds} - {HttpContext.Connection.Id}");
        stopwatch.Reset();
        var image = await response.Content.ReadAsByteArrayAsync();

        return new FileContentResult(image, "image/jpeg");
    }
}

您可以提高許多效率。

  • 使用全局HttpClient和處理程序,以便對同一服務器的請求可以多路復用。 這也可以防止套接字耗盡。
static HttpClient httpClient = new HttpClient(new SocketsHttpHandler()
{
    PooledConnectionIdleTimeout = TimeSpan.FromMinutes(10),
    PooledConnectionLifetime = TimeSpan.FromMinutes(10),
});
  • 使用HttpCompletionOption.ResponseHeadersRead以便僅緩沖標頭,否則必須緩沖完整響應。
    請注意,現在只在收到標頭之前進行計時。
[HttpGet(Name = "WMS")]
public async Task<ActionResult> GetWms()
{
    var query = HttpContext.Request.QueryString.Value;

    var stopwatch = Stopwatch.StartNew();
    using var response = await Client.GetAsync(BaseUrl + query, HttpCompletionOption.ResponseHeadersRead);

    stopwatch.Stop();
    Console.WriteLine($"{DateTime.Now:HH:mm:ss} - {stopwatch.ElapsedMilliseconds} - {HttpContext.Connection.Id}");
    stopwatch.Reset();

    var image = await response.Content.ReadAsByteArrayAsync();
    return new FileContentResult(image, "image/jpeg");
}
  • 僅當您的用例支持時,進一步的改進才可能起作用:將響應作為 stream 直接提供給FileStreamResult
[HttpGet(Name = "WMS")]
public async Task<ActionResult> GetWms()
{
    var query = HttpContext.Request.QueryString.Value;

    var stopwatch = Stopwatch.StartNew();
    // NO using, otherwise stream gets disposed
    var response = await Client.GetAsync(BaseUrl + query, HttpCompletionOption.ResponseHeadersRead);

    stopwatch.Stop();
    Console.WriteLine($"{DateTime.Now:HH:mm:ss} - {stopwatch.ElapsedMilliseconds} - {HttpContext.Connection.Id}");
    stopwatch.Reset();

    var image = await response.Content.ReadAsStreamAsync();
    return new FileStreamResult(image, "image/jpeg");
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM