反向代理出错后,会出现线程泄露?

2022-01-18 16:19:37 +08:00
 Pengxiguaa

我用 GO 写了一个很简单的反向代理程序,代码如下:

func main() {
	go func() {
		log.Fatal( http.ListenAndServe(":5050", nil))
	}()
	link, err := url.Parse("http://127.0.0.1:8908")
	if err != nil {
		log.Fatal(err)
	}
	log.Fatal( http.ListenAndServe(":10086", httputil.NewSingleHostReverseProxy(link)))
}

端口 8908 后边是一个 NodeJS socket.io 服务端,现在我通过 NodeJS 向 10086 端口同时发起 1000 个 websocket 连接,这些链接均会被代理到 8908 端口服务,然后将所有连接断开,重复几轮后可见控制台报如下错误:

2022/01/18 14:06:54 http: proxy error: dial tcp 127.0.0.1:8908: connectex: Only one usage of each socket address (protocol/network address/port) is normally permitted.

此时通过 windows 资源监视器可看到反向代理程序线程数为 298 ,通过 Process Explorer 可以看到 Handles 数为 1855 ,并且存在大量 Thread 。

再次建立连接再断开,反向代理程序的线程数持续增长,通过 pprof 可见 threadcreate 此时达到了惊人的 472 ,并一直保持。

似乎是系统端口数量限制导致的错误,然后错误导致线程未被回收?

我是 GO 新手,大家有遇到过这个问题吗?

17977 次点击
所在节点    Go 编程语言
14 条回复
pathletboy
2022-01-19 08:27:14 +08:00
不是你断开,反代和 8908 之间的连接就马上断开,和你系统的 TCP 的 TIME_WAIT 有关
参考 https://help.socketlabs.com/docs/how-to-fix-error-only-one-usage-of-each-socket-address-protocolnetwork-addressport-is-normally-permitted
Pengxiguaa
2022-01-19 11:56:26 +08:00
@pathletboy 感谢回复

目前我已将系统 TCP 释放时间( TcpTimedWaitDelay )调整为了 30 秒,并重新进行了测试。
几轮 websocket 连接-断开 之后,通过资源监视器看到反代程序积累了 465 个线程,此时 websoket 客户端处于断开的状态(进程已退出),8908 websocket 服务端正常运行,等待了 10 分钟线程数并未减少。紧接着关闭 8908 服务(退出进程),等待 10 分钟,线程数依然保持不变。
pathletboy
2022-01-19 11:59:13 +08:00
@Pengxiguaa 有条件的话可以测试下 caddy 反代是不是这样?
Pengxiguaa
2022-01-19 12:02:54 +08:00
官方库对这部分常用场景应该有考虑才对...现在没有头绪,待学习别人反代 websocket 之后再来更新。
Pengxiguaa
2022-01-19 12:03:34 +08:00
@pathletboy 好的,感谢提醒
Pengxiguaa
2022-01-19 14:19:59 +08:00
@pathletboy

在 windows 10 powershell 通过以下命令启动 caddy
```
# caddy_windows_amd64.exe reverse-proxy --from :10086 --to 127.0.0.1:8908
```
也会积累线程,奇怪了。

有时间再测测最多能积累多少线程,会不会导致进程崩溃的问题吧。
pathletboy
2022-01-19 14:57:24 +08:00
@Pengxiguaa import 加一行
_ "net/http/pprof"

跑起来看看这个有没什么发现
http://127.0.0.1:5050/debug/pprof/
liaohongxing
2022-01-21 09:22:53 +08:00
测试大量短链接端口不应该在 windows 测试。应该在 linux 测试 ,windows 本身就对 tcp 数量有限制 。其次就是 TCP TIME_WAIT ,不过 windows 的 TCP TIME_WAIT 也不知道怎么设
liaohongxing
2022-01-21 09:24:12 +08:00
你那报错我也遇到。随便用 hey 测几轮并发 ,windows 马上就报端口不够用了。
Pengxiguaa
2022-01-21 12:05:53 +08:00
@pathletboy 功力太浅,看不太明白,只记得在所有连接断开后,goroutine 数目恢复到个位数,而 threadcreate 依然居高不下。
Pengxiguaa
2022-01-21 12:13:26 +08:00
@liaohongxing TCP TIME_WAIT 设置看这里: https://docs.microsoft.com/en-us/biztalk/technical-guides/settings-that-can-be-modified-to-improve-network-performance

另外我们生产服务器只有 windows server ...
yeqown
2022-02-11 18:05:09 +08:00
@Pengxiguaa
这样反向代理 WS 是不行的吧,你想 HTTP 握手后升级到 WS ,HTTP 客户端怎么和 WS 服务器通信呢?协议都不一样了~
https://github.com/yeqown/fasthttp-reverse-proxy/blob/master/ws_reverseproxy.go#L71 供参考
yeqown
2022-02-11 18:07:04 +08:00
其次,看你的错误信息,我猜测你这个代理应该连握手都没办法完成吧~(协议问题),你测试结果有正确的响应吗?
Pengxiguaa
2022-05-24 11:24:29 +08:00
@yeqown ReverseProxy 模块中有 websocket 的实现,详情看 https://go.dev/src/net/http/httputil/reverseproxy.go:280,306

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

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

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

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

© 2021 V2EX