go net/http transport 内存泄漏

2023-04-03 10:00:19 +08:00
 aladdinding
		transport: &http.Transport{
			DialContext: proxy.DailContext,
			Proxy: func(req *http.Request) (*url.URL, error) {
				if proxyURL, ok := req.Context().Value(proxy.KeyProxyURL).(*url.URL); ok {
					return proxyURL, nil
				}
				return nil, nil
			},
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
			IdleConnTimeout:       15 * time.Second,
			ResponseHeaderTimeout: 10 * time.Second,
			TLSHandshakeTimeout:   10 * time.Second,
			ExpectContinueTimeout: 10 * time.Second,
			MaxIdleConnsPerHost:   3,
		},}

附上 pprof 图,

http://img.aladdinding.cn/202304030947153.png

集中在 bufio NewReader/Writer 是什么原因呢?


	pconn.br = bufio.NewReaderSize(pconn, t.readBufferSize())
	pconn.bw = bufio.NewWriterSize(persistConnWriter{pconn}, t.writeBufferSize())

	go pconn.readLoop()
	go pconn.writeLoop()
	return pconn, nil
2668 次点击
所在节点    问与答
23 条回复
picone
2023-04-03 10:47:14 +08:00
有内存变化趋势图吗?看了一下由 dialConn 代码内调用的 bufio 就这俩地,看起来是连接池使用的?
https://github.com/golang/go/blob/8edcdddb23c6d3f786b465c43b49e8d9a0015082/src/net/http/transport.go#L1769-L1770
aladdinding
2023-04-03 10:57:34 +08:00
@picone 是用了连接池,内存变化是缓慢增长,看 github 也是有一样的 issue ,但是也没讲出问题原因是什么
Reficul
2023-04-03 11:41:44 +08:00
MaxIdleConns
MaxIdleConnsPerHost
MaxConnsPerHost

这几个参数改大点试试看
picone
2023-04-03 11:42:38 +08:00
@aladdinding #2 你可以试试把连接池关闭了,验证是否就是连接池的问题。
另外你对外请求的 host 是多个的还是同一个?
lysS
2023-04-03 12:38:21 +08:00
1.5G 也叫内存泄漏吗?泄漏不是内存大,而是自增不减
lysS
2023-04-03 12:43:29 +08:00
默认的那个 buff 是 4KB
zizon
2023-04-03 13:06:31 +08:00
如果 buf.New 泄露的话,对应的应该 goroutine 也应该增长的.
transport.dialConnFor 是个 goroutine,看着是 req cancel 的时候会退出.

是请求多的时候有些没 cancel 掉导致?
sadfQED2
2023-04-03 13:10:33 +08:00
插眼,同样的全局 transport ,类似的问题,查了一年都没解决。现在是加监控自动重启。
sadfQED2
2023-04-03 13:11:11 +08:00
楼主解决了记得分享下啊
aladdinding
2023-04-03 15:36:45 +08:00
@picone transport 加了 DisableKeepAlives:true 就没有内存泄漏了,

但是我看代码,加了后会在 header 加入 connection:close ,如果目标网站识别到 close ,主动关闭连接的话,就用不了长连接了

对外请求是很多郁闷,而且还有很多代理,通过 connectMethodKey 来看,连接池会有很多连接,但是我设置了 IdleConnTimeout 为 15s 了,应该也不会出现内存泄漏
aladdinding
2023-04-03 15:37:34 +08:00
@aladdinding 对外请求是很多域名+不同的 http 代理
aladdinding
2023-04-03 15:37:57 +08:00
@sadfQED2 加了 DisableKeepAlives:true 临时解决的
aladdinding
2023-04-03 15:38:35 +08:00
@Reficul MaxIdleConns MaxIdleConns 默认都是 0 ,没有限制的
picone
2023-04-03 15:47:45 +08:00
@aladdinding #11 go 的连接池是按照 host 来计算 idle connection 的
aladdinding
2023-04-03 15:49:08 +08:00
@picone 准确的说还有 proxy

// connectMethod is the map key (in its String form) for keeping persistent
// TCP connections alive for subsequent HTTP requests.
//
// A connect method may be of the following types:
//
// connectMethod.key().String() Description
// ------------------------------ -------------------------
// |http|foo.com http directly to server, no proxy
// |https|foo.com https directly to server, no proxy
// |https,h1|foo.com https directly to server w/o HTTP/2, no proxy
// http://proxy.com|https|foo.com http to proxy, then CONNECT to foo.com
// http://proxy.com|http http to proxy, http to anywhere after that
// socks5://proxy.com|http|foo.com socks5 to proxy, then http to foo.com
// socks5://proxy.com|https|foo.com socks5 to proxy, then https to foo.com
// https://proxy.com|https|foo.com https to proxy, then CONNECT to foo.com
// https://proxy.com|http https to proxy, http to anywhere after that
type connectMethod struct {
_ incomparable
proxyURL *url.URL // nil for no proxy, else full proxy URL
targetScheme string // "http" or "https"
// If proxyURL specifies an http or https proxy, and targetScheme is http (not https),
// then targetAddr is not included in the connect method key, because the socket can
// be reused for different targetAddr values.
targetAddr string
onlyH1 bool // whether to disable HTTP/2 and force HTTP/1
}
Reficul
2023-04-03 16:26:01 +08:00
@aladdinding #13 MaxConnsPerHost 默认是 2 我记得好像,高并发情况下会打出来一堆连接
6IbA2bj5ip3tK49j
2023-04-03 16:52:19 +08:00
试试
httpClient.CloseIdleConnections()
777777
2023-04-03 17:37:52 +08:00
再告诉你个 bug ,官方库 net/http 的 websocket 和 http/2 存在不会退出造成协程和内存泄露。
777777
2023-04-03 17:40:47 +08:00
sadfQED2
2023-04-03 18:39:31 +08:00
@aladdinding emmm ,看来没办法,我们需要 keepalive

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/929315

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX