繁体   English   中英

Asp.net Core HttpClient 有很多 TIME_WAIT 或 CLOSE_WAIT 连接

[英]Asp.net Core HttpClient has many TIME_WAIT or CLOSE_WAIT connections

我使用AddHttpClient()依赖项注入将命名客户端添加到瞬态服务。 有时,当我在服务器上执行netstat -a时,我会看到许多连接以TIME_WAITCLOSE_WAIT状态打开。 我相信这些连接占用了太多资源,以至于其他TCP连接无法运行。 这可能吗? 有没有办法阻止这些,是否安全?

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        ServicePointManager.DefaultConnectionLimit = 200;

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        services.AddHttpClient(FirebaseService.FirebaseServiceClient, ConfigureFirebaseClient);

        services.AddTransient<FirebaseService>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseMvc();
    }

    void ConfigureFirebaseClient(HttpClient client)
    {
        var scopes = new string[] { "https://www.googleapis.com/auth/firebase.messaging" };

        Stream certificateStream = File.OpenRead("firebase-adminsdk.json");

        var serviceCredentials = GoogleCredential.FromStream(certificateStream);
        certificateStream.Close();

        var scopedCredentials = serviceCredentials.CreateScoped(scopes);
        var token = scopedCredentials.UnderlyingCredential.GetAccessTokenForRequestAsync().GetAwaiter().GetResult();
        client.SetBearerToken(token);
    }
}

public class FirebaseService
{
    public static string FirebaseServiceClient = "FirebaseServiceClient";

    private HttpClient _client;

    private readonly ILogger<FirebaseService> _logger;
    private readonly string _messagingUrl; 

    public FirebaseService(
        ILogger<FirebaseService> logger,
        IHttpClientFactory clientFactory)
    {
        _logger = logger;
        _messagingUrl = "https://fcm.googleapis.com/v1/projects/test2/messages:send";
        _client = clientFactory.CreateClient(FirebaseServiceClient);
    }

    public async Task<string> PostToFirebase(Dictionary<string, string> payload)
    {
        HttpResponseMessage result = null;
        string cont = null;
        try
        {
            var content = JsonConvert.SerializeObject(payload, Formatting.None);
            var stringContent = new StringContent(content, Encoding.UTF8, "application/json");

            result = await _client.PostAsync(_messagingUrl, stringContent);
            cont = await result.Content.ReadAsStringAsync();
            return cont;
        }
        finally
        {
            result?.Dispose();
        }
    }

}

public class ValuesController : ControllerBase
{
    private readonly IServiceProvider _serviceProvider;

    public ValuesController(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    [HttpGet]
    public async Task<IActionResult> Get()
    {
        var payload = new Dictionary<string, string>();
        List<Task> tasks = new List<Task>();
        for (int i = 0; i < 100; i++)
        {
            FirebaseService firebaseService = (FirebaseService)_serviceProvider.GetService(typeof(FirebaseService));
            var task = firebaseService.PostToFirebase(payload);
            tasks.Add(task);
            Console.WriteLine(i);
        }

        await Task.WhenAll(tasks.ToArray());

        //Console.WriteLine(result);

        return Ok();
    }

}

CLOSE_WAIT - 对方关闭了连接。

TIME_WAIT - 本地端点(您的应用)关闭了连接。

两个连接都会再保持几分钟,以防万一有来自另一端的延迟数据包。

“我相信这些连接占用了太多资源,其他TCP连接无法运行。这可能吗?” - 我想不是。 他们只是保持一个开放的端口。 这取决于有多少。 如果你有几百个,你会没事的。

“有没有办法阻止这些,安全吗?” - 我不这么认为。 它们都有相同的 PID,因此如果您尝试杀死其中一个,您的所有应用程序都将关闭。

期待更好的答案。

我意识到我遇到问题的连接不是来自client.PostAsync() 事实上,它们来自 IHttpClientFactory 的客户端配置操作中的 firebase 令牌身份验证请求。 所以这就是为什么当我切换到单例或静态属性时,不会多次调用CreateClient(clientName) ,问题就消失了。 虽然这在文档中写得很清楚,但我还是错过了。 Each time CreateClient is called, a new instance of HttpClient is created and the configuration action is called.

那是因为您可能使用了错误的生命周期管理方法。 HttpClient 存在套接字耗尽问题,因此应尽可能将其用作单例。

这篇 文章将回答你的问题。 另请阅读此处输入链接描述,了解有关 DNS 更改的解决方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM