引言:

  ASP.NET Core2.1 中出现了一个新的 HttpClientFactory 功能, 它有助于解决开发人员在使用 HttpClient 实例从其应用程序中访问外部 web 资源时可能遇到的一些常见问题。关于HttpClientFactory 到底解决了那些HttpClient的严重问题,下面是我罗列出来的(原文来自于:https://www.infoq.com/news/2016/09/HttpClient)

  (1)在处理HttpClient对象的时候不会立即关闭socket。

  (2)太多的实例影响性能

  (3)单例的HttpClient或者共享HttpClient实例,不遵守DNS 生存时间 (TTL) 设置。(这个问题我也不太明白,具体怎么重现这个问题,我下去再研究研究。)

HttpClientFactory这个小可爱,解决了上面的所有问题,他也是ASP.NET Core2.1最新特点之一,下面详细聊聊HttpClient存在的这些问题。

一、HttpClient存在的问题

  由于设计错误、bug 和文档不正确等因素, 导致在.Net中正确使用HttpClient 出奇的难。因此, 在生产环境中看起来正常工作的应用程序可能会在负载大的情况下产生性能和运行时故障的问题。

  为了理解我们为什么遇到这种情况, 我们首先要看另一个面向连接的类: SqlConnection。 这个类实现了IDisposable接口,所以绝大多数开发人员都是这样写的,实例如下:

  using (var con = new SqlConnection(connectionString)) {
    
con.open();
    
//use the connection here
  } //this closes the connection  

虽然,这个例子在解释HttpClient存在的问题不是很到位,但是使用这种方式,来写上面的代码,是没错的。如果你尝试这把这种模式应用到实现了IDisposable接口的HttpClient,则会遇到一些很奇怪的问题。具体的说,它会打开比实际需要更多的socket,加重了服务器的负载。此外使用using语句是不会关闭这些套接字的,相反,在应用程序停止使用它们时,会关闭几分钟。

Connection Pooling

回到 SqlConnection 示例中, 大多数面向连接的资源都是有连接池的。当您 "打开 " 数据库连接时, 它首先检查池中是否有可用的、未使用的连接。如果它找到一个, 将重用它, 而不是创建一个新的连接。

同样, 当您 "关闭 " SqlConnection 它只是将连接释放到链接池中。最终, 一个单独的进程可能会关闭长时间未使用的连接。

HttpClient 不这样做。当您处理它时, 它将启动关闭它所控制的套接字的过程。这意味着下次有请求时, 您必须经过一个全新的连接周期。如果您的网络有很高的延迟或您的连接是安全的, 则这会特别痛苦, 因为后者需要新一轮的 SSL/TLS 协商。

Closing a Socket Takes Four Minutes

如上所述,关闭套接字不是一个快速的过程。 当你“关闭”套接字时,你真正在做的是将它置于TIME_WAIT状态。 Windows将在此状态下保持连接240秒,以防万一剩余的数据包仍在传输中。

这使您更有可能耗尽可用套接字的数量,从而导致运行时错误,例如“无法连接到远程服务器.System.Net.Sockets.SocketException:每个套接字地址只有一种用法(协议/ 网络地址/端口通常是允许的“。

下面我们来实践一下,看看真相:

示例演示:(注意使用的是.Net Core 1.0)

using System;
using System.Net.Http;
using System.Threading.Tasks; namespace ConsoleApp2
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Starting connections");
for (int i = ; i < ; i++)
{
using (var client = new HttpClient())
{
var result = await client.GetAsync("http://aspnetmonsters.com/");
            Console.WriteLine(result.StatusCode);
          }
       }
      Console.WriteLine("Connections done");
      Console.ReadKey();
    }
  }
}

这将会打开10个请求,并以get的方式,去请求博客园,我们只打印出状态码。

输出结果:

到这个地步,可能我们就会很高兴,搞定!闪人!,真的搞定了吗?我的小可爱,下面我们使用netstat 工具并查看运行它的机器上的套接字状态,我们将看到:

看到没,我的应用程序已经执行完了,但是,仍然有很多链接在打开上面图示中的主机,它们都处于TIME_WAIT状态,这意味这我们在应用程序这边已经把链接关闭了,但是我们仍然在等待查看,是否有额外的数据包进来,使用这些链接。因为它们可能在网络的某个地方已经被延迟,下面我们来看一张TCT/IP图,该图引自(https://www4.cs.fau.de/Projects/JX/Projects/TCP/tcpstate.html)

Windows将在此状态下保持连接240秒(由[HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ Tcpip \ Parameters \ TcpTimedWaitDelay]设置)。 Windows可以快速打开新套接字的速度有限,因此如果您耗尽连接池,那么您可能会看到如下错误:

Unable to connect to the remote server
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.

在谷歌搜索会给你一些关于减少连接超时的可怕建议。 事实上,当在服务器上运行着正确使用HttpClient或类似构造的应用程序时,减少超时可能会导致其他不利后果。 我们需要了解“正确”意味着什么,并去修复底层的问题而不是去修补机器级的变量。

如果我们共享一个HttpClient实例,那么我们可以通过重用它们来减少套接字的浪费:

请注意,我们只为整个应用程序共享了一个HttpClient实例。 仍然可以正常工作(实际上由于套接字重用而快一点)。 Netstat现在只显示:

好了,总结一下:在.Net Core 1.0之前的版本,使用的时候需要注意下面的两点:

(1)确保你的HttpClient 是 static

(2)不要丢弃或包装HttpClient 在一个using块中。

小弟我才疏学浅,有不对的地方可以指出来,共同探讨。其实,我们一直使用using把它包起来,也是没错的,是因为HttpClient实现了IDisposable ,但是HttpClient就比较特殊,这不怪我们,文档就是错误的。

二、HttpClientFactory in ASP.NET Core 2.1就解决了上面所有的问题

HttpClientFactory 这个小可爱,就解决了上面的所有问题,她也是ASP.NET Core 2.1中最新特点之一,有了她我们就不用关心如何创建HttpClient,又如何释放它。关于如何使用它,博客园中的有介绍的,我这里就不再讲述了。

具体请参考:https://www.cnblogs.com/willick/p/9640589.html

三、总结

到这里该系列文章的第一篇就讲完了,有不对的地方,还请大佬们能指出来,共同探讨,好了,希望对你有所帮助,该系列文章,每周末更新,爱看不看,哈哈哈~~~~~~

参考文章:

(翻译)https://www.infoq.com/news/2016/09/HttpClient

(翻译)https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

作者:郭峥

出处:http://www.cnblogs.com/runningsmallguo/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

ASP.Net Core2.1中的HttpClientFactory系列一:HttpClient的缺陷的更多相关文章

  1. ASP.Net Core2.1中的HttpClientFactory系列二:集成Polly处理瞬态故障

    前言:最近,同事在工作中遇到了使用HttpClient,有些请求超时的问题,辅导员让我下去调研一下,HttpClinet的使用方式已经改成了之前博客中提到的方式,问题的原因我已经找到了,就是因为使用了 ...

  2. 在asp.net core2.1中添加中间件以扩展Swashbuckle.AspNetCore3.0支持简单的文档访问权限控制

    Swashbuckle.AspNetCore3.0 介绍 一个使用 ASP.NET Core 构建的 API 的 Swagger 工具.直接从您的路由,控制器和模型生成漂亮的 API 文档,包括用于探 ...

  3. 【翻译】asp.net core2.0中的token认证

    原文地址:https://developer.okta.com/blog/2018/03/23/token-authentication-aspnetcore-complete-guide token ...

  4. ASP.NET Core2.1 中如何使用 Cookie和Session

    https://blog.csdn.net/canduecho/article/details/80651853 ASP.NET Core2.1的官方项目模板在创建的Razor Pages和MVC项目 ...

  5. asp.net core2.0中异常的处理

    最近在开发中遇到一些关于如何抛出异常的困惑,在qq群里进行了讨论,有些人认为抛出异常是有理由的,可以对业务流程进行控制,而有些认为抛出异常会导致程序性能低下,我写一些自己的心得吧. 异常的全局处理 a ...

  6. 在ASP.NET Core2.0中使用百度在线编辑器UEditor(转)

    一.起因 UEditor是百度旗下的富文本编辑器,对于后端上传处理仅提供了Asp.Net 版的支持. 如果想在.Net Core项目中使用,那么后台上传接口需要重构. UEditorNetCore:百 ...

  7. Asp.Net Core2.2 源码阅读系列——控制台日志源码解析

      为了让我们第一时间知道程序的运行状态,Asp.Net Core 添加了默认的日志输出服务.这看起来并没有什么问题,对于开发人员也相当友好,但如果不了解日志输出的细节,也有可能因为错误的日志级别配置 ...

  8. asp.net core2.0中网站发布的时候,怎么样才配置才可以使视图文件不被打包进去?

    默认设置可真是坑~~ https://q.cnblogs.com/q/99680/

  9. asp.net core2.0中网站发布的时候,视图文件不被打包成dll

    项目csproj文件里面加 <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <Target ...

随机推荐

  1. 关于iframe跨域实践

    提要 项目中与到iframe子页面中需要通过top获取在父页面中的全局变量的需求,由于App部署的缘故,导致父页面和iframe子页面分别在不同的端口下,导致iframe跨域现象,通过查阅资料进行问题 ...

  2. javascript:面向对象和常见内置对象及操作

    本文内容: 面向对象 常见内置对象及操作 首发日期:2018-05-11 面向对象: JavaScript 是面向对象的编程语言 (OOP).OOP 语言使我们有能力定义自己的对象和变量类型. 对象是 ...

  3. Python 反射机制之hasattr()、getattr()、setattr() 、delattr()函数

    反射机制 先看看我对Java中反射机制的通俗理解:反射之中包含了一个“反”的概念,所以要想解释反射就必须先从“正”开始解释,一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产生实例化 ...

  4. 标注的SQL拼接语句

    方案一 exec sp_executesql N' SELECT T0.[WtmCode], T3.[opCode], T3.[opValue], T3.[CondId] FROM [dbo].[OW ...

  5. C#-泛型类型(十六)

    概述 泛型类和泛型方法兼具可重用性.类型安全性和效率,这是非泛型类和非泛型方法无法实现的 泛型通常与集合以及作用于集合的方法一起使用 泛型所属命名空间:System.Collections.Gener ...

  6. 修正Percona Monitoring Plugins for Zabbix的一处脚本Bug

    今天小试了一把Percona Monitoring Plugins for Zabbix模板,自己辛辛苦苦写的那一大堆Python脚本,貌似用这个模板全都覆盖到了.但是,我也发现最新的版本percon ...

  7. ArcGIS Server服务器监控

    最近项目上需要对服务器与ArcGISServer服务进行监控,做了一个初步的原型,实现了以下功能. 一.服务器监控 注册服务器 服务器运行状态监控 在线状态 CPU.内存.存储配置监控,由于现在很多采 ...

  8. SMM框架--maven创建web项目

    1.首先新建一个maven项目,看图: 2.按照以上步骤就可以创建一个maven项目,可以看到最下图的目录结构,但是这样的目录结构是不对的,需要做一些修改. 首先为了避免乱码,我们应该将项目编码换成U ...

  9. 3d max 动作Take 001改名

    问题描述 带动作的Fbx文件导入Unity之后,动作名字为Take 001,如下所示: 在max那边是没有办法改名的,只能在Unity中改名. 方法1 1. 选中动画文件,按Ctrl + D,复制一份 ...

  10. 基于WIN8.1:新手篇→tomcat安装配置

    一.JDK配置 下载安装JDK和tomcat 打开电脑属性,高级系统设置进行环境变量配置 新建系统变量,变量值为JDK安装路径,并在系统变量path最后加上“%JAVA_HOME%\bin;%JAVA ...