Gopher必读:HttpClient的两个坑位

简介: http是我们最常见的客户端/服务端传输协议,在golang中,默认的net/http包有一些坑位,需要调整以获得更加性能。在golang程序中,我也遇到因为不合理使用 http client导致的程序崩溃问题。

默认的HttpClient


默认的HttpClient不包含请求超时时间,如果你使用http.Get(url)或者&Client{}, 这将会使用http.DefaultClient,这个结构体内no timeout


假如发出请求的服务端API有问题:没有及时响应httpclient请求但是保持了连接, 在高并发情况下,打开的连接数会持续增长,最终导致客户端服务器资源到达瓶颈。


解决方案:不要使用默认的HTTPClient, 总是为HttpClient指定Timeout


client := &http.Client{
        Timeout: 10 * time.Second,
    }


HttpClient Timeout包括连接、重定向(如果有)、从Response Body读取的时间,内置定时器会在Get,Head、Post、Do 方法之后继续运行,直到读取完Response.Body。


b2d5e3c552fd68fc16e46043c0e49425.png


.NET HttpClient Timeout: The default value is 100,000 milliseconds (100 seconds).

02

默认的Http Transport


目前常见的HttpClient(.NET Core,golang) 都会有连接池的概念, 客户端会尽量复用池中已经建立的连接。


go的Transport 可理解为连接池中的连接。


// DefaultTransport is the default implementation of Transport and is
// used by DefaultClient. It establishes network connections as needed
// and caches them for reuse by subsequent calls. It uses HTTP proxies
// as directed by the $HTTP_PROXY and $NO_PROXY (or $http_proxy and
// $no_proxy) environment variables.
var DefaultTransport RoundTripper = &Transport{
    Proxy: ProxyFromEnvironment,
    DialContext: (&net.Dialer{
        Timeout:   30 * time.Second,
        KeepAlive: 30 * time.Second,
    }).DialContext,
    ForceAttemptHTTP2:     true,
    MaxIdleConns:          100,
    IdleConnTimeout:       90 * time.Second,
    TLSHandshakeTimeout:   10 * time.Second,
    ExpectContinueTimeout: 1 * time.Second,
}
// DefaultMaxIdleConnsPerHost is the default value of Transport's
// MaxIdleConnsPerHost.
const DefaultMaxIdleConnsPerHost = 2


默认的


golang的Http Client连接池有100个连接


每个连接默认的空闲时间90s(90s内有请求过来,可以复用该连接)


上面的KeepAlive是tcp探活的时间间隔,并不是我们HTTP连接复用的 Keep-Alive


有坑位的是DefaultMaxIdleConnsPerHost=2:每个主机(服务)保留的空闲连接数是2个。


这意味着,当首次针对某主机发出100个请求,这100个请求会同时利用连接池中的100个连接,之后因为这个限制,客户端被迫主动关闭98个连接,此时客户端机器会出现98 个time_wait(time_Wait会存在2MSL,大概2min,占用了机器资源),


新的请求被迫新开连接,然后立马主动关闭,只维持2个复用连接, 累积到最后造成客户端机器存在大量time_Wait的连接。


从我司实际项目看,造成CPU高涨,并且无法新开连接。


解决方案:不要使用默认Transport,增加MaxIdleConnsPerHost


本人回顾了.NET HttpClient,貌似不用刻意关注这个值。


实际上,.NET也存在这个MaxIdleConnectionPerServer配置👈[1],但是.NET Core这个PerServer被设置为int.maxvalue,所以我们无需关注,.NET真香。


03

我的收获


通过本文,我们谈到了golang HttpClient的2个坑位、由坑位导致的现象和排障思路,各位看官,有则改之无则加勉。


并且我们对比了.NET Core语言中HttpClient的默认配置,各位看官,家里有粮心中不慌。

相关文章
|
5月前
|
缓存 网络协议 安全
49. 【Android教程】HTTP 使用详解
49. 【Android教程】HTTP 使用详解
89 1
|
5月前
|
缓存 网络协议 Android开发
Android网络面试题之Http1.1和Http2.0
HTTP/1.1 引入持久连接和管道机制提升效率,支持分块传输编码和更多请求方式如PUT、PATCH。Host字段指定服务器域名,RANGE用于断点续传。HTTP/2变为二进制协议,实现多工处理,头信息压缩和服务器推送,减少延迟并优化资源加载。HTTP不断发展,从早期的简单传输到后来的高效交互。
70 0
Android网络面试题之Http1.1和Http2.0
|
6月前
|
域名解析 缓存 网络协议
JavaEE精选-HTTP
JavaEE精选-HTTP
46 1
|
6月前
|
缓存 Java API
HttpClient使用笔记干货满满
HttpClient使用笔记干货满满
105 0
|
缓存 网络协议 关系型数据库
学习http+Apache
学习http+Apache
144 0
|
SQL 域名解析 编解码
技术分享|Dnslog与Http外带
技术分享|Dnslog与Http外带
1417 0
|
网络协议 安全 Java
HTTP Client 学习笔记 (一) 初遇篇
HTTP Client 学习笔记 (一) 初遇篇
HTTP Client 学习笔记 (一) 初遇篇
|
Web App开发 存储 编解码
一文领略 HTTP 的前世今生(下)
一文领略 HTTP 的前世今生(下)
一文领略 HTTP 的前世今生(下)
|
存储 网络协议 程序员
一文领略 HTTP 的前世今生(上)
一文领略 HTTP 的前世今生(上)
一文领略 HTTP 的前世今生(上)
|
域名解析 缓存 安全
一文领略 HTTP 的前世今生(中)
一文领略 HTTP 的前世今生(中)
一文领略 HTTP 的前世今生(中)