Skip to content
This repository has been archived by the owner on Apr 9, 2020. It is now read-only.

OpenVZ VPS上内存占用过多 #3

Closed
yanunon opened this issue Jan 9, 2013 · 10 comments
Closed

OpenVZ VPS上内存占用过多 #3

yanunon opened this issue Jan 9, 2013 · 10 comments
Assignees

Comments

@yanunon
Copy link

yanunon commented Jan 9, 2013

在内存为128M、系统为64bit Debian6的OpenVZ VPS上只能保持25个左右的连接,每个连接使用了3个goroutine,算下来每个goroutine占用了1MB+的内存。

连接大于25个时,不能开辟新的内存空间,程序崩溃。

@ghost ghost assigned cyfdecyf Jan 9, 2013
@cyfdecyf
Copy link
Contributor

cyfdecyf commented Jan 9, 2013

OpenVZ 限制 virtual memory 的占用,Go runtime 会预先 allocate 一大块 virtual memory 供以后使用。

golang-nuts 上的讨论
https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/4Y-SO5QnGyY

minux 提到可以修改 go 源代码里预留 virtual memory 的代码来限制预留 VM 的大小
https://groups.google.com/d/msg/golang-nuts/4Y-SO5QnGyY/pKuOjYVh3n4J

另外如果 VPS 支持 vSwap,virtual memory 占用不会引起问题
https://groups.google.com/d/msg/golang-nuts/4Y-SO5QnGyY/rc1OEx7Zi3cJ

@clowwindy 提到可以试一下用 ulimit 限制内存使用。

我会试一下 minux 和 @clowwindy 提到的方法,看看究竟怎么解决这个问题。

@cyfdecyf
Copy link
Contributor

cyfdecyf commented Jan 9, 2013

ulimit -Sv 90000 的时候 shadowsocks-go 能够启动,再小的话启动会失败。

但设置 limit 之后程序运行会出奇怪的错误,shadowsocks-server DNS 解析会出错。

还是要试试看改 VM 分配的方法。

@clowwindy
Copy link
Contributor

Go DNS 解析应该是通过线程实现的。

http://news.ycombinator.com/item?id=4093859

除了这里提到的几个方案,还有个方案就是弄个 goroutine 池。

@cyfdecyf
Copy link
Contributor

根据 minux 和 @clowwindy 的建议,暂时考虑下面的解决方案:

  • 发布二进制文件时
    • 修改 $GOROOT/src/pkg/runtime/malloc.h,重新编译 go compiler 后再创建二进制文件。这可以避免程序刚启动时 OpenVZ 统计到占用大量内存
    • 编译时禁用 cgo,CGO_ENABLED=0 go install -a -v std,这样 Go runtime 可以使用 clone(2) 来创建线程,每个线程只需要 8KB 内存(Linux NPTL pthread_create(3) 创建的线程堆栈默认为 2MB)
    • 使用 Go 1.1 (应该快 release 了,在这之前可以看下 tip 是否稳定),由于引入非阻塞的 read/write syscall.{Read, Write}NB,网络性能应该稍有提升
  • 修改代码,用 goroutine pool 来做 dns 解析,限制线程数量
    • 如果将来 Go 解决了线程数过多的问题可能就不需要这个优化了

更多信息 https://groups.google.com/forum/?fromgroups=#!topic/golang-china/VXUI8ddxeCY

最近比较忙,得稍等一段时间才能 fix。

@yanunon
Copy link
Author

yanunon commented Jan 10, 2013

多谢~

@cyfdecyf
Copy link
Contributor

DNS 解析的 goroutine pool 已经在 4aae0ce 中加入。

@yanunon 我用了最新的 go tip,仅仅修改 src/pkg/runtime/malloc.h 中的 MHeapMap_Bits = 27 - PageShift 会导致 go 的测试无法全部通过。

禁用 CGO 之后编译得到的 server 程序 bss 大小仅 392K,但在我的 vps 上运行 VIRT 大概在 36M,依然会占用 30M 左右内存。

我倾向于尝试把 OpenVZ 转成支持 vSwap 的试试看,修改 go 的实现这个处理方法过于 hack。

@cyfdecyf
Copy link
Contributor

禁用 cgo 后,go 会使用自带的 name resolution library,从而不会发生创建过多线程的问题。

使用 shadowsocks-httpget 创建 1000 个并发连接,不使用 dnspool,server 运行在 64bit Debian 6 上测试 get 本地 nginx 的静态页面,测试结果

  • 禁用 cgo,最多有 8 个 shadowsocks-server 进程,VIRT 333M,RSS 75M
  • 启用 cgo,线程数达到 53,VIRT 3.9G,RSS 84M

或许编译时直接禁用 cgo 是更简单有效的解决方案,不过要看禁用 cgo 后 dns 解析是否会有什么问题。

@yanunon
Copy link
Author

yanunon commented Jan 15, 2013

修改了src/pkg/runtime/malloc.h,会导致测试失败,但是程序仍能正常运行,可能有隐藏的问题,毕竟测试没有完全通过。
直接禁用cgo的确是目前比较合适的方法。

@cyfdecyf
Copy link
Contributor

在支持 vswap 的 OpenVZ 主机上测试过,不会出现错误统计内存占用的问题。只是启动 shadowsocks-go 大概占用 2M 内存。

我会在 README 中加入相关说明。

@ddatsh
Copy link
Contributor

ddatsh commented Jan 23, 2015

咨询下现在官方的binary是怎么编译出来的呀

cappiewu pushed a commit to cappiewu/shadowsocks-go that referenced this issue Apr 10, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants