HttpClientFactory 使用说明 及 对 HttpClient 的回顾和对比
HttpClient 日常使用及坑点:
在 C# 中,平时我们在使用 HttpClient 的时候,会将 HttpClient 包裹在 using 内部进行声明和初始化,如:
using(var httpClient = new HttpClient())
{
//other codes
}
至于为什么?无外乎是:项目代码中就是这样写的,依葫芦画瓢/别人就是这样用的/在微软官方的 ASP.NET 教程中也是这么干的。
说的技术范点:当你使用继承了 IDisposable 接口的对象时,建议在 using 代码块中声明和初始化,当 using 代码段执行完成后,会自动释放该对象而不需要手动进行显示 Dispose 操作。
但这里,HttpClient 这个对象有点特殊,虽然继承了 IDisposable 接口,但它是可以被共享的(或者说可以被复用),且线程安全。从项目经验来看,倒是建议在整个应用的生命周期内,复用 HttpClient 实例,而不是每次 RPC 请求的时候就实例化一个。(之前在优化公司一个 web 项目的时候,也曾经因为 HttpClient 载过一次坑,后面我会进行简述。)
我们先来用个简单的例子做下测试,看为什么不要每次 RPC 请求都实例化一个 HttpClient:
public class Program
{
static void Main(string[] args)
{
HttpAsync();
Console.WriteLine("Hello World!");
Console.Read();
}
public static async void HttpAsync()
{
for (int i = 0; i < 10; i++)
{
using (var client = new HttpClient())
{
var result = await client.GetAsync("http://www.baidu.com");
Console.WriteLine($"{i}:{result.StatusCode}");
}
}
}
}
运行项目输出结果后,通过 netstate 查看下 TCP 连接情况:
- 虽然项目已经运行结束,但是连接依然存在,状态为 "TIME_WAIT"(继续等待看是否还有延迟的包会传输过来。)。
默认在 windows 下,TIME_WAIT 状态将会使系统将会保持该连接 240s。
- 这里也就引出了我上面说的载过的一次坑:在高并发的情况下,连接来不及释放,socket 被耗尽,耗尽之后就会出现喜闻乐见的一个错误:
#使用jemter压测复现错误信息:
Unable to connect to the remote serverSystem.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.
说白话:就是会出现“各种套接字问题”。(码WCF的童鞋可能更加记忆尤新,问题追根溯源都是换汤不换药。)
熊厂里面能够搜索出来的解决方法,基本都是“减少超时时间”,但人为减少了超时时间会出现各种莫名其妙的错误。且无法避免服务器迟早崩溃的问题。
可以通过注册表进行修改默认值:[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay])
那么如何处理这个问题?答案已经在上面说了,“复用 HttpClient”即可。如:
public class Program
{
private static readonly HttpClient _client = new HttpClient();
static void Main(string[] args)
{
HttpAsync();
Console.WriteLine("Hello World!");
Console.Read();
}
public static async void HttpAsync()
{
for (int i = 0; i < 10; i++)
{
var result = await _client.GetAsync("http://www.baidu.com");
Console.WriteLine($"{i}:{result.StatusCode}");
}
}
}
可以看到,原先 10 个连接变成了 1 个连接。(请不要在意两次示例的目标 IP 不同---SLB 导致的,都是百度的ip)
另外,因为复用了 HttpClient,每次 RPC 请求的时候,实际上还节约了创建通道的时间,在性能压测的时候也是很明显的提升。曾经因为这一举动,将 web 项目的 TPS 从单台 600 瞬间提升到了 2000+,页面请求时间也从 1-3s 减少至 100-300ms,甚是让测试组小伙伴膜拜(当然也包括了一些业务代码的细调。),但知道个中缘由后,一个小改动带来的项目性能提升。。。会让人上瘾:)
至于如何创建一个静态 HttpClient 进行复用,大家可以按项目实际来,如直接创建一个“全局”静态对象,或者通过各类 DI 框架来创建均可。
但这么调整 HttpClient 的引用后,依然存在一些问题可能会影响到你的项目(尚未影响到我:P),如:
- 因为是复用的 HttpClient,那么一些公共的设置就没办法灵活的调整了,如请求头的自定义。
- 因为 HttpClient 请求每个 url 时,会缓存该url对应的主机 ip,从而会导致 DNS 更新失效(TTL 失效了)
那么有没有办法解决 HttpClient 的这些个问题?直到我遇到了 HttpClientFactory,瞬间写代码幸福感倍升,也感慨新时代的童鞋们真的太幸福了,老一辈踩的坑可以“完美”规避掉了。
HttpClientFactory 优势:
HttpClientFactory 是 ASP.NET CORE 2.1 中新增加的功能。
- “完美”解决了我多年来遇到的这些坑,可以更加专注于业务代码。
- HttpClientFacotry 很高效,可以最大程度上节省系统 socket。(“JUST USE IT AND FXXK SHUT UP”
最新文章
- 后缀数组的倍增算法(Prefix Doubling)
- Ext动态加载Toolbar
- easyui datagrid 行右键生成 动态获取(toolbar) 按钮
- unique函数的作用
- 24.栈的push和pop序列[StackPushPopSequence]
- iOS 中的第三方库管理工具
- 用thinkphp进行微信开发的整体设计思考
- MongoDB 3: 使用中的问题,及其应用场景
- CF198 D2
- html-----015---HTML ASCII 参考手册
- codevs 4909 寂寞的堆(写的好丑0.0)
- java语言为什么能跨平台
- maven build时报错Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
- SQL Server中的连接查询(内连接、外连接、交叉连接)
- SQL数据库日志清理
- kafka监控工具之一--kafka-manager
- Nginx中间件使用心得(二)
- CH3301 同余方程
- 用Java实现多线程服务器程序
- Alpha Scrum1
热门文章
- Codeforces Round #568 (Div. 2)B
- 使用docker启动mysql
- python的is与==的区别
- 用kubeadm创建高可用kubernetes集群后,如何重新添加控制平面
- JavaScript面试核心考点(精华)
- java word转html 报错 org/apache/poi/xwpf/usermodel/IRunBody
- [深度学习]TensorFlow安装
- c++学习书籍推荐《C++编程思想第一卷》下载
- Ubuntu系统 apt-get update失败解决办法
- OpenCV多版本切换和配置--opencv 安装与卸载、添加 opencv_contrib modules 以及 OpenCv 多版本切换