runtime/cgo: pthread_create failed: Resource temporarily unavailable

1,398 views
Skip to first unread message

Wendal Chen

unread,
Oct 24, 2012, 9:54:30 PM10/24/12
to golang...@googlegroups.com
runtime/cgo: pthread_create failed: Resource temporarily unavailable
SIGABRT: abort
PC=0xffffe424

//然后是很长一堆的goroutine

程序是一个http服务,类似与代理服务器,所以goroutine的数量不少

编译环境 Ferda 14  x86
运行环境 OpenSUSE 11.4 x86 4核CPU

程序启动时会调用
runtime.GOMAXPROCS(runtime.NumCPU())

这个异常是运行一段时间之后才出现的, 就出现过一次,暂没能重现. dmesg没看到error输出

请问一下这个异常是我代码的问题呢,还是golang的某些限制或者bug吗?  谢谢


--
Wendal Chen
GuangDong China

Wendal Chen

unread,
Jan 20, 2013, 6:28:10 AM1/20/13
to golang...@googlegroups.com
这个已经解决了

问题在于每次proxy一个请求, golang都会查dns, DialTimeout执行超时后并不会终止dns查询.

在我使用的环境中, 3G网络不稳定,导致dns经常挂住不返回结果, 累计到一定数量后, 就报这种异常然后崩溃了


解决方法就是加个dns cache,在proxy之前,先自行将域名从cache中查出来. 上线跑了一周, 没有再发现类似崩溃的情况.

steve wang

unread,
Jan 20, 2013, 6:37:38 AM1/20/13
to golang...@googlegroups.com
这个问题minux已经解释过了,是因为在系统调用阻塞时大量生成内核级线程导致的。
你用cache只是减少系统调用的几率,也可以自己做一个队列来限制dns查询的数量防止内核级线程超出数量限制。

Chen Yufei

unread,
Jan 20, 2013, 6:54:52 AM1/20/13
to golang...@googlegroups.com
On 2013年1月20日Sunday at 下午7:37, steve wang wrote:
> 这个问题minux已经解释过了,是因为在系统调用阻塞时大量生成内核级线程导致的。
> 你用cache只是减少系统调用的几率,也可以自己做一个队列来限制dns查询的数量防止内核级线程超出数量限制。

我之前写过一个做 dns 查询的 goroutine pool,用固定数量的 goroutine 来做 dns 查询,从而限制由 dns 查询阻塞而可能创建的线程数量。
http://github.com/cyfdecyf/dnspool

这个解决方案的问题是如果所有 dns 查询都 block,可能会导致整个程序 block。

如果程序不用 cgo 的话可以禁用 cgo,这样 net package 做 dns 解析的时候会使用 go 自己实现的 dns client,所以不会出现创建过多线程的问题,也不会出现整个程序 block 的问题。
>
> On Sunday, January 20, 2013 7:28:10 PM UTC+8, Wendal Chen wrote:
> > 这个已经解决了
> >
> > 问题在于每次proxy一个请求, golang都会查dns, DialTimeout执行超时后并不会终止dns查询.
> >
> > 在我使用的环境中, 3G网络不稳定,导致dns经常挂住不返回结果, 累计到一定数量后, 就报这种异常然后崩溃了
> >
> >
> > 解决方法就是加个dns cache,在proxy之前,先自行将域名从cache中查出来. 上线跑了一周, 没有再发现类似崩溃的情况.
> >
> > 在 2012年10月25日上午9:54,Wendal Chen <wenda...@gmail.com (javascript:)>写道:
> > > runtime/cgo: pthread_create failed: Resource temporarily unavailable
> > > SIGABRT: abort
> > > PC=0xffffe424
> > >
> > > //然后是很长一堆的goroutine
> > >
> > > 程序是一个http服务,类似与代理服务器,所以goroutine的数量不少
> > >
> > > 编译环境 Ferda 14 x86
> > > 运行环境 OpenSUSE 11.4 x86 4核CPU
> > >
> > > 程序启动时会调用
> > > runtime.GOMAXPROCS(runtime.NumCPU())
> > >
> > > 这个异常是运行一段时间之后才出现的, 就出现过一次,暂没能重现. dmesg没看到error输出
> > >
> > > 请问一下这个异常是我代码的问题呢,还是golang的某些限制或者bug吗? 谢谢
> > >
> > >
> > > --
> > > Wendal Chen
> > > GuangDong China
> >
> >
> >
> >
> > --
> > Wendal Chen
> > GuangDong China
>
>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net (http://irc.freenode.net) #golang-china
> @golangchina
>
>
>



steve wang

unread,
Jan 20, 2013, 7:25:33 AM1/20/13
to golang...@googlegroups.com


On Sunday, January 20, 2013 7:54:52 PM UTC+8, Yufei Chen wrote:
On 2013年1月20日Sunday at 下午7:37, steve wang wrote:
> 这个问题minux已经解释过了,是因为在系统调用阻塞时大量生成内核级线程导致的。
> 你用cache只是减少系统调用的几率,也可以自己做一个队列来限制dns查询的数量防止内核级线程超出数量限制。

我之前写过一个做 dns 查询的 goroutine pool,用固定数量的 goroutine 来做 dns 查询,从而限制由 dns 查询阻塞而可能创建的线程数量。
http://github.com/cyfdecyf/dnspool

这个解决方案的问题是如果所有 dns 查询都 block,可能会导致整个程序 block。
并不是完全block,等goroutine完成前一个dns查询就可以进行后续的查询了。
我并不觉得这是一个问题,毕竟你不可能无限制地发起系统调用而又期望系统调用不会阻塞。

Chen Yufei

unread,
Jan 20, 2013, 7:47:02 AM1/20/13
to golang...@googlegroups.com
On 2013年1月20日Sunday at 下午8:25, steve wang wrote:
>
>
> On Sunday, January 20, 2013 7:54:52 PM UTC+8, Yufei Chen wrote:
> > On 2013年1月20日Sunday at 下午7:37, steve wang wrote:
> > > 这个问题minux已经解释过了,是因为在系统调用阻塞时大量生成内核级线程导致的。
> > > 你用cache只是减少系统调用的几率,也可以自己做一个队列来限制dns查询的数量防止内核级线程超出数量限制。
> >
> >
> > 我之前写过一个做 dns 查询的 goroutine pool,用固定数量的 goroutine 来做 dns 查询,从而限制由 dns 查询阻塞而可能创建的线程数量。
> > http://github.com/cyfdecyf/dnspool
> >
> > 这个解决方案的问题是如果所有 dns 查询都 block,可能会导致整个程序 block。
> 并不是完全block,等goroutine完成前一个dns查询就可以进行后续的查询了。

嗯,我前面说错了。只是可能会有很多进行 dns 查询的 goroutine block,其他的不受影响。
> 我并不觉得这是一个问题,毕竟你不可能无限制地发起系统调用而又期望系统调用不会阻塞。

并发的 dns 查询数量的确没必要太多,我的 dnspool 里默认是 32。

我觉得严格来说 dns 阻塞的问题不是系统调用阻塞的问题,而是 C 库的 getaddrinfo 没法用异步或者 non-blocking 的方式去调用。(参见 $GOROOT/src/pkg/net/cgo_unix.go)。
cgo 调用很多 C 库函数都会有这个问题,所以必须用创建线程的方式来处理。

go 自己的实现的 dns client 由于跟 dns server 通信是自己创建 udp 连接,所以 fd 可以设置成 non-blocking 的模式。(参见 $GOROOT/src/pkg/net/dnsclient_unix.go)

Wendal Chen

unread,
Jan 23, 2013, 11:21:34 PM1/23/13
to golang...@googlegroups.com
我用的是DialTimeout, 超时之后,应该把线程销毁吧? 算不算一个bug呢?

当然,这个问题也可以归咎于linux下的dns默认是没有cache

IRC:  irc.freenode.net     #golang-china
@golangchina



Chen Yufei

unread,
Jan 24, 2013, 12:12:21 AM1/24/13
to golang...@googlegroups.com
2013/1/24 Wendal Chen <wenda...@gmail.com>
我用的是DialTimeout, 超时之后,应该把线程销毁吧? 算不算一个bug呢?
 
从我观察到的现象来看 go runtime 创建出来的线程不会退出,应该是留着以后使用。
这一点没有看代码确认过。


当然,这个问题也可以归咎于linux下的dns默认是没有cache

嗯。我一般都会在 Linux 上用 dnsmasq,Ubuntu 12.04 上默认就是这么做的。

--
Best regards,
Chen Yufei

Chen Yufei

unread,
Jan 24, 2013, 12:24:56 AM1/24/13
to golang...@googlegroups.com
2013/1/24 Chen Yufei <cyfd...@gmail.com>

2013/1/24 Wendal Chen <wenda...@gmail.com>
我用的是DialTimeout, 超时之后,应该把线程销毁吧? 算不算一个bug呢?
 
从我观察到的现象来看 go runtime 创建出来的线程不会退出,应该是留着以后使用。
这一点没有看代码确认过。

当然,这个问题也可以归咎于linux下的dns默认是没有cache

嗯。我一般都会在 Linux 上用 dnsmasq,Ubuntu 12.04 上默认就是这么做的。
确认了一下,12.04 虽然用了 dnsmasq,但是 cache-size 默认设置成 0,相当于把 dns cache disabled 了,不知道是出于什么考虑……

Long Bai

unread,
Jan 24, 2013, 12:39:43 AM1/24/13
to golang...@googlegroups.com
使用cgo + cares来进行dns查询吧
Reply all
Reply to author
Forward
0 new messages