golang http client 关闭重用连接两种方法
同事有个模块会定期获取宿主机上的所有容器信息,代码中使用http client 请求docker engine获取容器信息。运行后收到用户反馈,程序导致系统fd泄漏,修复后代码如下,比原来代码多了一句 req.Close=true
client := &http.Client{
Timeout: time.Duration(timeout) * time.Millisecond,
Transport: &http.Transport{
Dial: unixDial,
},
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("NewRequest(): url = %s, err = %s", url, err)
}
req.Close = true // fd leak without setting this
resp, err := client.Do(req)
...
因为我自己有个清理容器数据的代码也有类似逻辑。代码如下,但是这个清理容器的模块是运行一次就退出的(磁盘资源紧张时才运行) 所以没有这个问题。
tr := &http.Transport{Dial: fakeDial, }
client := &http.Client{Transport: tr}
resp, err := client.Get("http://localhost/containers/json")
if err != nil {
return nil, err
}
defer resp.Body.Close()
翻了下源码发现这段注释
// Close indicates whether to close the connection after
// replying to this request (for servers) or after sending this
// request and reading its response (for clients).
//
// For server requests, the HTTP server handles this automatically
// and this field is not needed by Handlers.
//
// For client requests, setting this field prevents re-use of
// TCP connections between requests to the same hosts, as if
// Transport.DisableKeepAlives were set.
Close bool
http 1.1默认是保持keep-alive 的,所以如果每次请求都new 一个xin的client,就会造成fd泄漏。 按照注释,在new client时,把keep-alive 设置为disable 就可以解决这个问题。修改后代码如下
tr := &http.Transport{Dial: fakeDial, DisableKeepAlives: true}
client := &http.Client{Transport: tr}
resp, err := client.Get("http://localhost/containers/json")
if err != nil {
return nil, err
}
defer resp.Body.Close()
问题1 req.Close 和transport DisableKeepAlives 如何实现 http keep-alive:close 的? 如何达到相同目的的? 问题2 使用时怎么样更科学 更安全? 长连接? 短连接?