Go语言 连接池相关总结:HTTP、RPC、Redis 和数据库等

本文作者 Xargin,个人博客:https://xargin.com/ 。
http 标准库服务端请求处理package mainimport ( "io" "log" "net/http")func sayhello(wr http.ResponseWriter, r *http.Request) { wr.Header()["Content-Type"] = []string{"Application/json"} io.WriteString(wr, "hello")}func main() { http.HandleFunc("/", sayhello) http.ListenAndServe(":9090", nil)}
Go语言 连接池相关总结:HTTP、RPC、Redis 和数据库等

文章插图
 
1-1
每一个请求启动一个 goroutine,读取完毕之后,调用用户传入的 handler(没有的话就用默认的),在同一连接进行 response 响应 。整体上是个 request/response loop 模型 。
客户端连接池type Transport struct { idleMu       sync.Mutex closeIdle    bool                                // user has requested to close all idle conns idleConn     map[connectMethodKey][]*persistConn // most recently used at end idleConnWait map[connectMethodKey]wantConnQueue  // waiting getConns idleLRU      connLRU connsPerHostMu   sync.Mutex connsPerHost     map[connectMethodKey]int connsPerHostWait map[connectMethodKey]wantConnQueue // waiting getConns    // MaxIdleConns controls the maximum number of idle (keep-alive) // connections across all hosts. Zero means no limit. MaxIdleConns int // MaxIdleConnsPerHost, if non-zero, controls the maximum idle // (keep-alive) connections to keep per-host. If zero, // DefaultMaxIdleConnsPerHost is used. MaxIdleConnsPerHost int // MaxConnsPerHost optionally limits the total number of // connections per host, including connections in the dialing, // active, and idle states. On limit violation, dials will block. // // Zero means no limit. MaxConnsPerHost int // IdleConnTimeout is the maximum amount of time an idle // (keep-alive) connection will remain idle before closing // itself. // Zero means no limit. IdleConnTimeout time.Duration}transport 和 client 是一一对应,每个 tranport 内有自己的 connpool,idleConn 的结构是:map[connectMethodKey][]*persistConn,这个 map 的 key 是个数据结构:
// connectMethodKey is the map key version of connectMethod, with a// stringified proxy URL (or the empty string) instead of a pointer to// a URL.type connectMethodKey struct { proxy, scheme, addr string onlyH1              bool}proxy 地址 + 协议 + 地址,以及是否只支持 http1,构成该 map 的 key,proxy 地址是完整的 proxy 地址,比如 export HTTP_PROXY=localhost:1081,则该地址为用户提供的字符串 。scheme 一般是 http:// 或 https:// 之类的字符串,addr 包含完整的域名(或 IP)和端口 。
getConn:
Go语言 连接池相关总结:HTTP、RPC、Redis 和数据库等

文章插图
 
2
在 http2 中,同一个连接可以被重复使用,所以 http2 的逻辑里,该连接被返回后仍然保持在连接池里 。是否可以重复使用由 pconn.alt 来决定 。
tryPutIdleConn3
如果有正在等待连接的 goroutine,那么就把这条连接 deliver 给相应的 goroutine,这会触发相应的 ready 操作,使阻塞中的 goroutine 被唤醒继续处理请求 。
否则将连接放回到 Transport 的 idleConn 和 idleLRU 中 。
readloop 和 writeloopfunc (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *persistConn, err error) { go pconn.readLoop() go pconn.writeLoop() return pconn, nil}所以每个 conn 都会有相应的 readloop 和 writeloop,因此每个连接至少有两个 goroutine 。


推荐阅读