在Golang中使用net/http包发起HTTP请求时,连接复用是影响客户端性能的核心因素。如果每次请求都新建Client或忽略Transport配置,底层TCP连接无法复用,会显著增加延迟与系统开销。通过合理优化可以实现高效的连接池管理。

为什么需要优化连接复用
默认的http.Client虽然可以复用连接,但很多开发者会写出如下代码:
package main
import (
"net/http"
"io/ioutil"
)
func badRequest() {
// 每次请求都创建新的Client,无法有效复用连接
client := &http.Client{}
resp, _ := client.Get("https://ipipp.com/api")
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
_ = body
}
上述写法在高并发下会产生大量短连接,带来握手成本和端口占用问题。
复用Client与配置Transport
应当全局复用同一个Client实例,并通过自定义Transport来控制连接池行为。
package main
import (
"net/http"
"time"
)
var client = &http.Client{
Transport: &http.Transport{
MaxIdleConns: 100, // 最大空闲连接数
MaxIdleConnsPerHost: 10, // 每个host最大空闲连接
IdleConnTimeout: 90 * time.Second, // 空闲连接超时
DisableKeepAlives: false, // 开启keep-alive
},
Timeout: 10 * time.Second,
}
func goodRequest() {
resp, err := client.Get("https://ipipp.com/api")
if err != nil {
return
}
defer resp.Body.Close()
}
关键参数说明
- MaxIdleConns:控制全局空闲连接总量,避免无限制缓存。
- MaxIdleConnsPerHost:限制单主机空闲连接,防止某host占用全部连接。
- IdleConnTimeout:空闲连接回收时间,平衡复用率与资源占用。
使用连接复用后的注意事项
若服务端要求关闭keep-alive,可将DisableKeepAlives设为true,但通常不建议。另外,当请求体较大或需自定义DNS时,可结合DialContext优化:
package main
import (
"net"
"net/http"
"time"
)
func newClient() *http.Client {
return &http.Client{
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConnsPerHost: 20,
},
}
}
性能对比参考
| 方式 | 平均延迟 | 连接数 |
|---|---|---|
| 每次新建Client | 高 | 多 |
| 复用Client+调优Transport | 低 | 少 |
通过复用Client并正确设置Transport参数,Golang的net/http客户端能够稳定复用TCP连接,从而显著提升吞吐并降低资源消耗。