http - net/http : request canceled (Client. 等待 header 时超时)为什么/该怎么办?

标签 http azure asp.net-web-api go azure-web-app-service

TL:DR - 查看编辑 2 中与代码 http 客户端代码等效的 C#,导致〜相同的问题,因此 Go http.Client 不是真正的问题,而是 C# Web API 一旦部署到 Azure...

部署到 Azure Web App [2x 标准 S3] 后,我的 C# Web API 性能非常差。起初我问的是:Go 的 http.Client 超时,但用 C# 和 NodeJs 编写类似的客户端给出了相同的结果。

这是我的http.Client:

func getWebClient() *http.Client {
    var netTransport = &http.Transport{
        Dial: (&net.Dialer{
            Timeout: 5 * time.Second,
        }).Dial,
        TLSHandshakeTimeout:   10 * time.Second,
        MaxIdleConnsPerHost:   2000,
        ResponseHeaderTimeout: 10 * time.Second,
    }

    var netClient = &http.Client{
        Timeout:   time.Second * 10,
        Transport: netTransport,
    }

    return netClient
}

我遇到的错误:

net/http:请求已取消(等待 header 时超出了 Client.Timeout)

它可以是 GET、POST、PUT。我收到了这些错误,但使用curl 运行失败的GET 立即得到了回复。

这是我用来调用 API 的示例 Get 函数:

func get(path string, result interface{}) error {
    req, err := http.NewRequest("GET", webDALAPIURL+path, nil)
    if err != nil {
        return err
    }

    req.Header.Set("Content-Type", "application/json")

    wc := getWebClient()
    res, err := wc.Do(req)
    if err != nil {
        return err
    }
    defer res.Body.Close()

    if res.StatusCode >= 400 {
        return fmt.Errorf("[GET] %d - %s", res.StatusCode, webDALAPIURL+path)
    }

    decoder := json.NewDecoder(res.Body)
    return decoder.Decode(result)
}

有趣的是,当 API 在本地运行时从未遇到过这些错误。 API 是一个 C# ASP.NET Web API 应用程序。

我开始出现大量 TLS 握手错误,因此我删除了 Azure 应用程序端点的 https。现在我收到此错误。

我正在跟踪应用程序的日志,但没有发生任何事情[正在调用 API]。似乎 Go 无法对同一主机进行多次调用。我不是在一个 cmd 中使用 goroutine 并在另一个 cmd 中使用它们,两者都会导致相同的错误。

当 API 在同一网络中的 Windows 计算机上运行时,在开发过程中从未出现过该错误。

编辑1:

请注意,80-85% 的请求运行良好,场景是这样的(伪代码):

for item in items {
  http get /item/{id} => works 90% of the time, 10% timeout

  change item properties

  http PUT /item/{id} => works 80% of the time
}

我在 get() 函数中添加了重试,因此如果发生超时,它将重试 get,这似乎有效。不过,我根本不喜欢这种解决方法。

另请注意,我们正在讨论返回超时的快速 GET,当我从 curl 运行它们时,它的时间 < 1 秒。对于 PUT 来说也是如此,这些都是高度简单的数据库 SELECT * FROM TABLE WHERE ID = {id} AND UPDATE。

运行 API 的 Azure Web 应用程序是 2 个标准 S3 实例。

事实是,GET 的重试工作看起来很成功,这很可能是 API/Azure 应用程序没有承受负载,为了简单起见,这是不可能的,我们正在谈论少于 10 个请求/秒。

另一点不可忽视,在开发服务器上运行时,使用相同的 Azure SQL 数据库,因此 SELECT/UPDATE 性能在开发服务器和 Azure Web App 上应该完全相同。

编辑2:

比较相同的 C# Web API 从本地到 Azure 的速度令人不安。我编写了一个类似的 C# http 客户端来测试 Azure 与本地 Web API。

class Program
{
  static int fails = 0;
  static void Main(string[] args)
  {
    for (int i = 0; i < 2000; i++)
    {
      get(i);
    }
    Console.WriteLine("completed: " + fails.ToString());
    Console.ReadLine();
  }
  static void get(int id)
  {
    id += 22700;
    var c = new HttpClient();

    var resp = c.GetAsync("http://myapphere.azurewebsites.net/api/users/" + id).Result;
    if (!resp.IsSuccessStatusCode)
    {
      Console.WriteLine("");
      fails++;
      Console.WriteLine(string.Format("error getting /users status code {0}", resp.StatusCode));
    }
    else
    {
      Console.Write(".");
    }
  }
}

针对Azure运行这个控制台应用程序我可以清楚地看到Go在哪里超时,它非常慢,没有返回错误,但是Console.Write(".");打印需要很长时间,是周期性的,打印速度比停止时快 3-4 倍。

再次将其更改为 localhost:1078 使用相同的数据库,不会出现暂停,并且 Console.Write(".") 的打印速度是 Azure 的 20 倍.

这怎么可能?

编辑3:

刚刚在Web api上添加了全局错误处理程序,可能是由于抛出太多异常而导致的不严谨。添加了 Trace.TraceError 和我的 azure site log tail 它,再次没有显示任何内容。

我什至可以说,本地 Web API 的运行速度比 Azure 标准 S3 实例的运行速度快 25-30 倍。显然这不是真的,但 Web API 非常简单,我不知道如何让 Azure 全速运行它。

最佳答案

我认为你可能想使用上下文、go 例程和 channel 之类的东西来不锁定你的 main.与 C# 中的 Task 类似,它也为您提供更高的吞吐量和性能。

https://marcofranssen.nl/tags/go/

你可以找到我写的一堆博客文章。我也有 C# 背景,这些博客是我学到的一些经验教训。我在博客中确实提到了 C# 与 Go 方法,这样您就可以轻松进行比较。

查看 go 例程和优雅的网络服务器帖子。您可能会在那里找到答案。

此外,您的 C# 实现由于调用 .Result 而被阻塞

您应该使用异步等待,利用任务使代码更加高效。

我预计您的 C# 服务器可能也没有使用 Task 作为返回类型,这意味着它将无法处理大量连接。一旦您在那里使用任务并在新线程中旋转代码,新线程也将能够处理更多并发请求并可能更频繁地成功。因此,基本上在单独的线程/任务中执行数据库操作,并确保处理数据库连接以防止内存泄漏。

这只是一个假设,因为我注意到这篇文章中的客户端代码也没有正确使用它。因此,如果我的假设有误,请原谅我。

关于http - net/http : request canceled (Client. 等待 header 时超时)为什么/该怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38557968/

相关文章:

http - 为什么使用 trackbacks 而不是 HTTP Referer header ?

http - 在 root 和 rest on/api 上提供静态内容

azure - 如何授予 Azure VM 访问本地网络资源的权限

Azure Active Airectory (AAD) 服务到服务身份验证

apache - apache中的这个配置是什么意思?

HTTPS 通信失败 ABAP

c# - 如何使用 app.config 将 Azure Key Vault 连接到 C# Windows 服务

c# - 在我们的服务器之间强制执行 TLS 1.2 后,Web Api 调用现在失败

c# - WebAPI 无法解析 multipart/form-data post

asp.net - 如何在同一服务器上托管 Web 应用程序和 API,同时将它们分开?