V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
aladdinding
V2EX  ›  问与答

go net/http transport 内存泄漏

  •  
  •   aladdinding · 2023-04-03 10:00:19 +08:00 · 2377 次点击
    这是一个创建于 388 天前的主题,其中的信息可能已经有所发展或是发生改变。
    • 使用的是全局的 transport
    		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,
    		},}
    
    • 每次 resp.Body 也 close 了

    附上 pprof 图,

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

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

    • goroutine 数量也没有暴增,数量稳定在 3000-4000 ,下面是 transport 代码
    
    	pconn.br = bufio.NewReaderSize(pconn, t.readBufferSize())
    	pconn.bw = bufio.NewWriterSize(persistConnWriter{pconn}, t.writeBufferSize())
    
    	go pconn.readLoop()
    	go pconn.writeLoop()
    	return pconn, nil
    
    23 条回复    2023-04-03 21:33:33 +08:00
    picone
        1
    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
        2
    aladdinding  
    OP
       2023-04-03 10:57:34 +08:00
    @picone 是用了连接池,内存变化是缓慢增长,看 github 也是有一样的 issue ,但是也没讲出问题原因是什么
    Reficul
        3
    Reficul  
       2023-04-03 11:41:44 +08:00
    MaxIdleConns
    MaxIdleConnsPerHost
    MaxConnsPerHost

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

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

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

    对外请求是很多郁闷,而且还有很多代理,通过 connectMethodKey 来看,连接池会有很多连接,但是我设置了 IdleConnTimeout 为 15s 了,应该也不会出现内存泄漏
    aladdinding
        11
    aladdinding  
    OP
       2023-04-03 15:37:34 +08:00
    @aladdinding 对外请求是很多域名+不同的 http 代理
    aladdinding
        12
    aladdinding  
    OP
       2023-04-03 15:37:57 +08:00
    @sadfQED2 加了 DisableKeepAlives:true 临时解决的
    aladdinding
        13
    aladdinding  
    OP
       2023-04-03 15:38:35 +08:00
    @Reficul MaxIdleConns MaxIdleConns 默认都是 0 ,没有限制的
    picone
        14
    picone  
       2023-04-03 15:47:45 +08:00
    @aladdinding #11 go 的连接池是按照 host 来计算 idle connection 的
    aladdinding
        15
    aladdinding  
    OP
       2023-04-03 15:49:08 +08:00   ❤️ 1
    @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
        16
    Reficul  
       2023-04-03 16:26:01 +08:00
    @aladdinding #13 MaxConnsPerHost 默认是 2 我记得好像,高并发情况下会打出来一堆连接
    xgfan
        17
    xgfan  
       2023-04-03 16:52:19 +08:00
    试试
    httpClient.CloseIdleConnections()
    777777
        18
    777777  
       2023-04-03 17:37:52 +08:00
    再告诉你个 bug ,官方库 net/http 的 websocket 和 http/2 存在不会退出造成协程和内存泄露。
    777777
        19
    777777  
       2023-04-03 17:40:47 +08:00
    sadfQED2
        20
    sadfQED2  
       2023-04-03 18:39:31 +08:00 via Android
    @aladdinding emmm ,看来没办法,我们需要 keepalive
    sadfQED2
        21
    sadfQED2  
       2023-04-03 18:49:29 +08:00
    @777777
    @aladdinding

    看了一下我们代码,ForceAttemptHTTP2 设置的 true ,keepalive 开启,我淦。
    sadfQED2
        22
    sadfQED2  
       2023-04-03 18:50:47 +08:00
    @777777 #18 http/2 不退出会造成协程和内存泄露,这个问题在哪有讨论吗,能否给个来源呢?
    bigNewsMaker
        23
    bigNewsMaker  
       2023-04-03 21:33:33 +08:00
    ➕1
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3452 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 11:29 · PVG 19:29 · LAX 04:29 · JFK 07:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.