同事有个模块会定期获取宿主机上的所有容器信息,代码中使用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