Go的httptrace包能否跟踪连接关闭及归还连接池的事件?
问题解答
1. PutIdleConn 回调未触发的原因
PutIdleConn回调仅对HTTP/1.x协议的连接生效,你测试用的目标地址https://golang.org/默认会协商使用HTTP/2协议,HTTP/2的多路复用连接管理逻辑不会触发该回调。- 你可以通过强制关闭HTTP/2的方式验证效果,修改客户端初始化逻辑即可:
package main import ( "crypto/tls" "io" "io/ioutil" "log" "net/http" "net/http/httptrace" "time" ) func main() { trace := &httptrace.ClientTrace{ GotConn: func(info httptrace.GotConnInfo) { log.Printf("GotConn(%+v)", info) }, PutIdleConn: func(err error) { log.Printf("PutIdleConn(%+v)", err) }, } // 强制使用HTTP/1.x协议 client := &http.Client{ Transport: &http.Transport{ ForceAttemptHTTP2: false, TLSNextProto: map[string]func(string, *tls.Conn) http.RoundTripper{}, }, } for i := 0; i < 10; i++ { req, err := http.NewRequest("GET", "https://golang.org/", nil) if err != nil { log.Fatal(err) } ctx := httptrace.WithClientTrace(req.Context(), trace) req = req.WithContext(ctx) res, err := client.Do(req) if err != nil { log.Fatal(err) } if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { log.Fatal(err) } res.Body.Close() time.Sleep(10 * time.Millisecond) } time.Sleep(1000 * time.Millisecond) }
修改后运行即可看到PutIdleConn回调正常触发,回调参数err为空代表连接成功归还到连接池;如果出现连接池满、连接损坏等需要销毁连接的场景,err会携带对应的错误信息。
2. 连接关闭事件的感知方案
标准库httptrace没有提供直接的连接关闭回调,你可以通过自定义封装实现统计:
- 重写
http.Transport的DialContext方法,对创建出的net.Conn做代理包装,在代理的Close方法被调用时记录连接关闭事件 - 如果需要适配HTTP/2协议,可以通过扩展HTTP/2传输层的钩子逻辑实现连接关闭事件的监听
内容的提问来源于stack exchange,提问作者Igor Kupczyński
相关产品推荐
相关产品推荐

