从http.Transport看连接池的设计
版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 本文基于Golang 1.17.6 1.前言 之前萌叔曾在文章 imroc/req 连接池使用须知 提及过Golang标准库net/http提供的连接池http.Transport,但是是浅尝辄止。 本文萌叔想从http.Transport出发来谈谈一个连接池设计应该考虑哪些问题? 2.连接池的功能特征 下图是针对Grpc和Thrift压测结果(见参考资料1)。我么可以看出,长连接相比与短连接相比,QPS大概提升了1倍多。这是因为长连接减少连接建立的所需的3次握手。 要对长连接进行管理,特别是对闲置的长连接进行管理,就不可避免的引入连接池。 特征 需要一个连接时,并不一定真的创建新连接,而是优先尝试从连接池选出空闲连接;如果连接池对应的连接为空,才创建新连接。 销毁并不是真的销毁,而是将使用完毕的连接放回连接池中(逻辑关闭)。 这里引出了几个问题。 Q1:获取连接阶段,我们有没有办法知道从连接池中取出的空闲连接(复用)是有效的,还是无效的? Q2:把使用完毕的连接放回连接池的阶段,空闲连接数量是否要做上限的约束。如果空闲连接数量有上限约束且空闲连接的数量已经达到上限。那么把连接放回连接池的过程,必然需要将之前的某个空闲连接进行关闭,那么按照什么规则选择这个需要关闭的连接。 Q3:放置在连接池中的连接,随着时间的流逝,它可能会变成无效连接(stale)。比如由于Server端定时清理空闲连接。那么为了确保连接池中连接的有效性,是否需要引入定时的检查逻辑? 3.net/http中连接池的实现 net/http中连接池的实现代码在 net/http/transport.go 中 获取连接 Transport.RoundTrip() -> Transport.getConn() 放回连接(逻辑关闭) Response.Body.Close() -> bodyEOFSignal.Close() -> Transport.tryPutIdleConn() 为了约束空闲连接的数量,连接池引入了几个变量: MaxIdleConns MaxIdleConns controls the maximum number of idle (keep-alive) connections across all hosts. 所有host总的最大空闲连接数量,默认值是100 MaxIdleConnsPerHostif non-zero, controls the maximum idle (keep-alive) connections to keep per-host。 针对每个Host能够保持的最大空闲连接数量。默认值是2 这个是一个比较有意思的变量,因为默认情况,所有的HTTP请求都使用同一个连接池,由于MaxIdleConns存在,如果针对某个Host的 连接占用了大量空间,那么针对其它Host的连接可能就没有存储空间了。 MaxConnsPerHost MaxConnsPerHost optionally limits the total number of connections per host, including connections in the dialing, active, and idle states. 默认值是0,表示不限制。 ...