System.Net.HttpClient:SendAsync 失败,OperationCanceledException 没有通过网络的 http 请求

Fra*_*k59 5 c# dotnet-httpclient .net-core

我们System.Net.Http.HttpClient用于 k8s 内部微服务之间的调用。

  • 操作系统 Linux(在 docker 内部)
  • dotnet 目标框架:netcoreapp2.1
  • 服务器:红隼
  • 协议:http

几天前,我们注意到 http 调用的非常奇怪的行为:微服务之间的某些调用(接近 2-3%)因错误而失败

System.OperationCanceledException: The operation was canceled.
   at System.Net.Http.HttpClient.HandleFinishSendAsyncError(Exception e, CancellationTokenSource cts)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at OurCode.HttpServiceClient.GetStringResponseAsync(String methodUri, HttpMethod httpMethod)
   ...another our code...
Run Code Online (Sandbox Code Playgroud)

在我们的 http 调用超时后(3 秒)。但是没有关于被叫服务内部调用的日志。

我们启用了 packetbeat 来跟踪 http 请求,并且还注意到,没有任何从调用方服务到被调用方服务的 http 请求被执行。此服务的 CPU、内存和网络一直正常。

我们用于 http 调用的代码的简化版本如下所示:

public async Task<string> GetStringResponseAsync(String methodUri,  HttpMethod httpMethod)
{
    int timeoutInMilliseconds = 3000;
    var tokenSource = new CancellationTokenSource();
    var rm = new HttpRequestMessage(httpMethod, methodUri);
    Task<HttpResponseMessage> httpTask = HttpClient.SendAsync(rm, tokenSource.Token);
    tokenSource.CancelAfter(timeoutInMilliseconds);
    HttpResponseMessage response = await httpTask;
    await EnsureSuccessStatusCode(response);
    return await response.Content.ReadAsStringAsync();
}
Run Code Online (Sandbox Code Playgroud)

关于什么问题会在没有通过网络请求 http 的情况下导致这种奇怪行为的任何想法,我该怎么做才能进一步调查?

Gab*_*uci 6

这只是意味着 Web 服务没有响应。

HttpClient超时后抛出TaskCanceledException, (继承自OperationCanceledException)。它不直观,对我(和其他人)没有任何意义,但不幸的是它就是这样做的。

有一些关于它的讨论在这里(有几个人提到了一些解决方法,从一个真正的区别超时取消,如果你愿意)。