You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6 API请求发送至接收间3秒延迟的优化问询

问题描述

我正在对自身API的流程耗时进行测量,编写了一段可同时调用API n次的简单代码:

private HttpClient _httpClient { get; } = new HttpClient();

[TestCase]
public async Task Perf_ExecuteAuthThreads()
{
    await Parallel.ForEachAsync(Enumerable.Range(0, NB_THREADS).ToList(), new ParallelOptions
    {
        MaxDegreeOfParallelism = NB_THREADS
    }, async (item, cancellationToken) => await CreateAuthThread(item));
}

private async Task CreateAuthThread(int i)
{
    string tokenAuth = string.Empty;

    DateTime startDate = DateTime.Now;

    var stopWatchGlobal = new Stopwatch();
    var stopWatchDetails = new Stopwatch();
    
    stopWatchGlobal.Restart();
    try
    {
        stopWatchDetails.Restart();

        using var request = new HttpRequestMessage(HttpMethod.Post, RequestFactory.GetRoute(RequestFactory.RequestType.AUTH));
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        request.Content = JsonContent.Create(RequestFactory.CreateRequest(RequestFactory.RequestType.AUTH));

        // Authenticate Method
        using HttpResponseMessage response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
        response.EnsureSuccessStatusCode();

        stopWatchDetails.Stop();

        if (response.IsSuccessStatusCode)
        {
            tokenAuth = (await response.Content.ReadFromJsonAsync<Token>())!.JwtToken;
        }
        else
        {
            string responseAsString = await response.Content.ReadAsStringAsync();
            //Assert.Fail("Internal server Error : {0}", responseAsString);
        }
    }
    catch {  /* DO NOTHING */ }

    stopWatchGlobal.Stop();

    // Get business transaction Guid
    var transactionGuid = new JwtSecurityToken(jwtEncodedString: tokenAuth).Claims.FirstOrDefault(x => x.Type == Constants.JWT_CLAIMS_TRANSACTION_GUID)?.Value ?? null;

    // Thread Id;TransactionGuid;Begin Date;End Date;Auth Duration;Business Duration;Result Business;Total Duration;
    Console.WriteLine($"\"{i}\";\"{transactionGuid}\";\"{startDate.ToString("MM/dd/yyyy hh:mm:ss.fff tt")}\";\"{DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss.fff tt")}\";\"{stopWatchDetails.ElapsedMilliseconds}\";\"{(tokenAuth != string.Empty ? true : false)}\";\"{stopWatchGlobal.ElapsedMilliseconds}\"");
} 

在本地计算机与服务器时钟同步的前提下,我发现API请求从发送到被API接收之间存在约3秒的延迟,但API响应到本地调用结束之间不存在该延迟。我知晓传输层会产生耗时,但3秒的时长过于高昂,且我认为这并非通信初始化的“突发时间”。我的API及测试代码均基于.NET 6,使用TLS连接(HTTPS),请求与响应均为常规JSON格式,数据量不大。请问是否有办法缩短该延迟?


解决方案建议

1. 优化HttpClient连接配置

默认HttpClient的连接池设置可能无法适配高并发场景,可通过SocketsHttpHandler调整:

var handler = new SocketsHttpHandler
{
    MaxConnectionsPerServer = NB_THREADS, // 匹配并发数,避免连接排队
    PooledConnectionLifetime = TimeSpan.FromMinutes(5), // 定期回收旧连接,避免资源泄漏
    PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2),
    EnableTlsSessionResumption = true // 启用TLS会话复用,减少重复握手耗时
};
private HttpClient _httpClient { get; } = new HttpClient(handler);

如果不需要自动重定向,可添加AllowAutoRedirect = false减少不必要的处理步骤。

2. 排查TLS握手瓶颈

3秒延迟大概率和TLS握手过程相关:

  • 强制TLS版本:显式指定优先使用TLS 1.3/1.2,避免版本协商耗时:
    handler.SslOptions = new SslClientAuthenticationOptions
    {
        EnabledSslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12
    };
    
  • 验证证书信任链:若使用自签名证书,默认的证书验证可能产生延迟,可临时禁用验证(仅测试用)确认:
    handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
    
    若延迟消失,需配置正确的证书信任链。

3. 精准定位延迟节点

当前计时逻辑无法区分网络传输与服务器处理的耗时,需补充日志:

  • 在API端添加请求到达时间、响应开始时间的日志,和本地startDate对比,确认延迟是否真的发生在网络阶段。
  • 启用.NET的System.Net.Http日志类别,查看连接建立、TLS握手的详细耗时,定位具体瓶颈。

4. 优化并行调用逻辑

  • 调整并发数:如果NB_THREADS过大,可能导致本地端口耗尽或服务器限流,建议从10、20开始逐步增加,找到最优并发值。
  • 替换并行方式:I/O密集型操作可改用Task.WhenAll,减少线程池调度开销:
    [TestCase]
    public async Task Perf_ExecuteAuthThreads()
    {
        var tasks = Enumerable.Range(0, NB_THREADS).Select(i => CreateAuthThread(i));
        await Task.WhenAll(tasks);
    }
    

5. 排查网络环境问题

  • DNS解析测试:用nslookup测试API域名的解析耗时,若延迟高,可在本地hosts文件绑定域名与IP,跳过DNS解析。
  • 单请求验证:先测试单个请求的耗时,确认是否仅并发场景出现延迟,排除服务器端限流或队列问题。
  • 防火墙/代理检查:本地或服务器的防火墙、代理是否存在流量过滤规则,导致请求被延迟处理。

内容的提问来源于stack exchange,提问作者BaptX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 13:35:18