代码背景
使用 golang 验证代理 Ip,代码主要作用如下
- 通过扫描然后扫描得到一个 ip 文件,每行一个代理 ip
- 遍历文件按行读取 每行使用代理 ip 发起一个 http 请求 验证之后输出日志
- client 数量通过 bufferd channel 控制 小于 ulimit -n
问题
ip 文件内容一般是 100W 行以上,程序运行一段时间之后会出现socket: too many files open
我的尝试
最开始以为是持久连接的问题,就设置了keep-alive: false,设置之后发现还是有问题
使用 pprof 调试发现很多 goroutine 卡在这里,但是此时 channel 长度是比设定值要小的,代表是可以接收数据,等于是老的 goroutine 没有释放,新的 goroutine 一直在创建
internal/poll.runtime_pollWait(0x7f004f1ca2f8, 0x72, 0xffffffffffffffff)
/usr/local/go/src/runtime/netpoll.go:184 +0x55
internal/poll.(*pollDesc).wait(0xc0029e6f18, 0x72, 0x1000, 0x1000, 0xffffffffffffffff)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc0029e6f00, 0xc002938000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
/usr/local/go/src/internal/poll/fd_unix.go:169 +0x1cf
net.(*netFD).Read(0xc0029e6f00, 0xc002938000, 0x1000, 0x1000, 0x0, 0x0, 0xc001f21f18)
/usr/local/go/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc0017ae198, 0xc002938000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
/usr/local/go/src/net/net.go:184 +0x68
bufio.(*Reader).fill(0xc00180ca20)
/usr/local/go/src/bufio/bufio.go:100 +0x103
bufio.(*Reader).ReadSlice(0xc00180ca20, 0xa, 0xc001f21840, 0xc001f21888, 0x40c0c6, 0xc00087e120, 0x90)
/usr/local/go/src/bufio/bufio.go:359 +0x3d
bufio.(*Reader).ReadLine(0xc00180ca20, 0x8, 0xc0006c6a80, 0x7f0051656460, 0x0, 0x2, 0xc329f8)
/usr/local/go/src/bufio/bufio.go:388 +0x34
net/textproto.(*Reader).readLineSlice(0xc001f21960, 0xc00087e120, 0xc002938000, 0x7f004f3698c8, 0xc0027bdd01, 0x101000000950280)
/usr/local/go/src/net/textproto/reader.go:57 +0x6c
net/textproto.(*Reader).ReadLine(...)
/usr/local/go/src/net/textproto/reader.go:38
net/http.ReadResponse(0xc00180ca20, 0xc00106b400, 0x1000, 0xc002938000, 0xc0017ae198)
/usr/local/go/src/net/http/response.go:161 +0xd1
net/http.(*Transport).dialConn(0xc002945a40, 0x94cd60, 0xc000024100, 0xc0029e6d80, 0x8b4508, 0x5, 0xc002685940, 0x11, 0x0, 0xc000288fa8, ...)
/usr/local/go/src/net/http/transport.go:1544 +0x85a
net/http.(*Transport).dialConnFor(0xc002945a40, 0xc000ec1ce0)
/usr/local/go/src/net/http/transport.go:1308 +0xdc
created by net/http.(*Transport).queueForDial
/usr/local/go/src/net/http/transport.go:1277 +0x41d
因为阅读 golang http 源码太过于吃力,所以只大概跟了一下代码,我理解这段代码是创建 connection 请求并返回, 想请教一下各位这个 connection 不释放的 具体原因到底是为什么