我下面有一个简单的程序,它是一个简单的HTTP客户端和服务器。我正在测试 Go 1.11 中引入的MaxConnsPerHost
中的http.Transport
是否按广告要求工作。但是,当我运行代码超过10-30分钟时,已建立的连接会慢慢超过设置的MaxConnsPerHost
。我在做错什么吗?
package main
import (
"io/ioutil"
"log"
"net"
"net/http"
"time"
)
func main() {
// Server
//
go func() {
if err := http.ListenAndServe(":8081", http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hi"))
},
)); err != nil {
log.Fatal(err)
}
}()
// Client settings
//
c := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
MaxConnsPerHost: 50,
},
}
// Worker loop
//
threads := 500
for i := 0; i < threads; i++ {
go func() {
for {
req, err := http.NewRequest("GET", "http://localhost:8081", nil)
if err != nil {
log.Fatal(err)
}
res, err := c.Do(req)
if err != nil {
log.Fatal(err)
}
if _, err := ioutil.ReadAll(res.Body); err != nil {
log.Fatal(err)
}
res.Body.Close()
}
}()
}
var done chan bool
<-done
log.Println("Done")
}
长时间运行后,netstat
报告的ESTABLISHED连接已超过50。
P.S。我们的其中一项服务存在问题,即使我们已正确关闭响应的正文,该服务也会严重泄漏已建立的连接。目前,它是使用 Go 1.10 构建的,我希望 Go 1.11 MaxConnsPerHost
是一个解决方案,但它似乎在重负载下也会裂开。