Reputation: 364
I've got a server using Asp.Net Core, and I am having trouble with delays when using HTTPS. When only fetching a few images, each request takes around 20ms to process. However when I make 125 requests simultaneously they slow down to 30-80ms (acceptable) when using HTTP, and down to 130-850ms (unacceptable) when using HTTPS.
I've done some debugging and the slowdown occurs when my server makes the http call to the WMS server.
Adding a custom socket handler cut the delay down from 4000-6000ms to the current 130-850ms so that helped a lot, but the delay is still a bit much.
PS: The server will do a bit more than simply proxying the queries, so I can't simply use a dedicated proxy server for that role.
Here's a minimal example of the server code:
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");
}
}
Upvotes: 6
Views: 3828
Reputation: 71578
There are a number of efficiencies you can make.
HttpClient
and handler, so that requests to the same server can multiplex. This also prevents socket exhaustion.static HttpClient httpClient = new HttpClient(new SocketsHttpHandler()
{
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(10),
PooledConnectionLifetime = TimeSpan.FromMinutes(10),
});
HttpCompletionOption.ResponseHeadersRead
so that only the headers are buffered, otherwise the full response has to be buffered.[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");
}
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");
}
Upvotes: 2