使用代理时去泄漏goroutines

时间:2018-05-15 07:56:32

标签: go memory-leaks goroutine

请帮我解决我的问题。我写了代码检查代理。一般情况下,我运行50个goroutines,每个goroutine从那时起从通道获取代理并检查它是否有效并从我的测试页面得到正确的响应。 每个goroutine都建立了这种关系

请求---->代理--->我的测试页--->测试我的测试页面中的内容。

功能检查这种关系是什么:

    // GetAndCheckURL get test page via proxy and check its body.
func GetAndCheckURL(c *http.Client, urlStr string) ([]byte, error) {
    resp, err := c.Get(urlStr)
    if err != nil {
        return nil, fmt.Errorf("request error: %v", err)

    }
    defer func() {
        if err := resp.Body.Close(); err != nil {
            packageLogger.Neverf("can't close response body, error: %v", err)
        }
    }()
    if body, err := ioutil.ReadAll(resp.Body); err != nil {
        packageLogger.Neverf("Can't read response body, URL '%s', error: %v, response statusCode: %d, status: %s\n", urlStr, err, resp.StatusCode, resp.Status)
        return nil, err
    } else if !bytes.Contains(body, []byte("<!--proxy_test")) {
        return nil, errors.New("invalid body")
    } else {
        return body, nil
    }
}

因为每个goroutines检查不同的代理,我不能使用单个http.Transport和http.Client结构。此函数GetAndCheckURL使用其http.transport(带代理)获取其http.client。 此功能通过此代码在我的员工中运行

    // readProxyWorker worker read proxy from chan.
func readProxyWorker(DB *storm.DB, workerNum int, conf config.CheckTaskConfig, ownIP string, proxyWaitChan <-chan proxy.Proxy, m proxy.CheckMetrics) {
    for i := 0; i < workerNum; i++ {
        go func() {
            var err error
            for p := range proxyWaitChan {
                // HERE RUN FUNCTION WHAT CHECK PROXIES
            }
        }()
    }
}

但问题是对于socks5代理我的漏洞goroutines。

 goroutine 160801 [IO wait, 915 minutes]:
internal/poll.runtime_pollWait(0x7fb2ab337410, 0x72, 0xc4206b96a8)
    /usr/local/Cellar/go/1.10.1/libexec/src/runtime/netpoll.go:173 +0x57
internal/poll.(*pollDesc).wait(0xc420c29998, 0x72, 0xffffffffffffff00, 0xb2e180, 0xe34418)
    /usr/local/Cellar/go/1.10.1/libexec/src/internal/poll/fd_poll_runtime.go:85 +0x9b
internal/poll.(*pollDesc).waitRead(0xc420c29998, 0xc422915e00, 0x2, 0x13)
    /usr/local/Cellar/go/1.10.1/libexec/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Read(0xc420c29980, 0xc422915ee0, 0x2, 0x13, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.10.1/libexec/src/internal/poll/fd_unix.go:157 +0x17d
net.(*netFD).Read(0xc420c29980, 0xc422915ee0, 0x2, 0x13, 0x0, 0x0, 0xe7c080)
    /usr/local/Cellar/go/1.10.1/libexec/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc4214ec1b8, 0xc422915ee0, 0x2, 0x13, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.10.1/libexec/src/net/net.go:176 +0x6a
io.ReadAtLeast(0x7fb2ab62d868, 0xc4214ec1b8, 0xc422915ee0, 0x2, 0x13, 0x2, 0xa99f60, 0x0, 0x7fb2ab62d868)
    /usr/local/Cellar/go/1.10.1/libexec/src/io/io.go:309 +0x86
io.ReadFull(0x7fb2ab62d868, 0xc4214ec1b8, 0xc422915ee0, 0x2, 0x13, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.10.1/libexec/src/io/io.go:327 +0x58
vendor/golang_org/x/net/proxy.(*socks5).connect(0xc4208b6690, 0xb367c0, 0xc4214ec1b8, 0xc42083cd60, 0x11, 0xb367c0, 0xc4214ec1b8)
    /usr/local/Cellar/go/1.10.1/libexec/src/vendor/golang_org/x/net/proxy/socks5.go:113 +0x2f5
vendor/golang_org/x/net/proxy.(*socks5).Dial(0xc4208b6690, 0xabaa03, 0x3, 0xc42083cd60, 0x11, 0xc42083ce80, 0x12, 0xb367c0, 0xc4214ec1b8)
    /usr/local/Cellar/go/1.10.1/libexec/src/vendor/golang_org/x/net/proxy/socks5.go:75 +0xf3
net/http.(*Transport).dialConn(0xc420e1eff0, 0xb32400, 0xc420020078, 0xc420c29580, 0xc420024780, 0x5, 0xc42083cd60, 0x11, 0xae8d10, 0xc4229ee7b8, ...)
    /usr/local/Cellar/go/1.10.1/libexec/src/net/http/transport.go:1176 +0x6f7
net/http.(*Transport).getConn.func4(0xc420e1eff0, 0xb32400, 0xc420020078, 0xc421205a70, 0xc4209fa7e0)
    /usr/local/Cellar/go/1.10.1/libexec/src/net/http/transport.go:957 +0x78
created by net/http.(*Transport).getConn
    /usr/local/Cellar/go/1.10.1/libexec/src/net/http/transport.go:956 +0x363
    goroutine 18553 [chan receive, 27 minutes]:
net/http.(*Transport).getConn.func2.1(0x1a7c8900, 0x19b8ff40, 0x84f7388)
    /usr/local/go/src/net/http/transport.go:946 +0x41
created by net/http.(*Transport).getConn.func2
    /usr/local/go/src/net/http/transport.go:945 +0x61

我不知道我的错误在哪里。只有在为连接(或ReadDeadline和WriteDeadline)添加截止日期时,我才能解决此问题。但是我希望通过超时来解决我的问题。我尝试了许多超时变种,但存在这种泄漏。 在我的http.Transport中,DisablekeepAlive为true,net.Dialer和http.Client有超时。

请帮帮我。

1 个答案:

答案 0 :(得分:1)

我有一个类似的问题,也有泄漏goroutines的问题。 第一个与Dialer中的KeepAlive超时有关,另一个与TLSHandshakeTimeout有关。有时我的程序被卡住了。以下代码应帮助您避免这种情况。希望对您有帮助)

&http.Transport{
        DialContext: (&net.Dialer{
            Timeout:   5 * time.Second,
            KeepAlive: 5 * time.Second,
            DualStack: true,
        }).DialContext,
        TLSHandshakeTimeout:   2 * time.Second,
        ResponseHeaderTimeout: 2 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
        DisableKeepAlives:     true,
    }