too many open files 的问题怎么解决?

Server 用Golang开发,使用 MongoDB位数据库,mgo 作为 DB driver。 有少量的Web 页面,Go的Http html/template开发的,

最近总是出现这个问题,应该怎么办? server.go:1553: http: Accept error: accept tcp [::]:80: too many open files

PS:我不想简单的增加rlimit的值,我的直觉,那没有解决根本的bug。

共 9 个回复


shaovie

是不是有句柄泄露? 看看 /proc/$pid/fd/ 下面

# 0

qkevin123

我也觉得应该是什么地方的资源泄漏造成,可是无从下手。。。。。。

# 1

qkevin123

使用mgo driver,每一次,读/写数据之后,需要关闭相应的collection吗?没有发现有什么close resource相关的方法呀。

# 2

qkevin123

现在服务器正常,在 /proc/$pid/fd/ 下面大约有200多个socket链接。这正常吗?

目前还处于测试阶段,没有用户正式使用。

# 3

gihnius

如果你用所有 request 共享 db session ,可以在程序退出时再关闭. 你也可以为每个 request 建立 session, 这样要在 request 完成前退出 session.

我用下面的代码:

    var InitSession *mgo.Session
    var db_url ...
    var db_name ...

    func NewSession() *mgo.Session {
        if InitSession == nil {
            var err error
            InitSession, err = mgo.Dial(db_url)
            if err != nil {
                panic(err)
            }
        }
        InitSession.SetMode(mgo.Monotonic, true)
        return InitSession.Clone()
    }

    func withCollection(collection string, s func(*mgo.Collection) error) error {
        session := NewSession()
        defer session.Close()
        c := session.DB(db_name).C(collection)
        return s(c)
    }

实际情况跟共享一个 session 时 还没发现 很大的区别!如果处理请求比较简单,可能共享 session 更快。

# 4

qkevin123

多谢各位帮忙分析。

关于数据库,我是使用的共享 session。

在 /proc/$pid/fd/ 下面,有这么多socket链接,是不是说明,这些socket链接没有关闭所造成? 我发现这里的socket会持续增加,说明这里存在很大的问题。

lrwx------ 1 root root 64 11月 8 09:50 44 -> socket:[587740]

lrwx------ 1 root root 64 11月 9 14:10 440 -> socket:[889549]

lrwx------ 1 root root 64 11月 9 14:10 441 -> socket:[895623]

lrwx------ 1 root root 64 11月 9 14:10 442 -> socket:[905374]

lrwx------ 1 root root 64 11月 9 14:10 443 -> socket:[857996]

lrwx------ 1 root root 64 11月 9 14:10 444 -> socket:[914200]

lrwx------ 1 root root 64 11月 9 14:10 445 -> socket:[912151]

lrwx------ 1 root root 64 11月 9 15:59 446 -> socket:[919757]

lrwx------ 1 root root 64 11月 9 15:59 447 -> socket:[923843]

lrwx------ 1 root root 64 11月 9 14:10 448 -> socket:[892747]

lrwx------ 1 root root 64 11月 9 14:10 449 -> socket:[937657]

lrwx------ 1 root root 64 11月 8 09:50 45 -> socket:[605546]

我想在golang server 和MongoDB数据库在同一台物理机器上,只用了一个共享session, 并且在一开始就使用 session.DB(db_name)获取了一个共享的 *mgo.Database 变量放在那里。 每次读写数据库都是从这个共享的 *mgo.Database 变量获取collection,这个应该没有什么问题吧?

另外一部分就是Golang监听HTTP请求,这些请求都来自手机客户端,golang处理完成之后,返回给客户端。 我现在怀疑,是这部分代码出了问题,导致socket没能及时close。可是这个如何下手调试/分析呢?

# 5

qkevin123

好了,搞定了。使用Nginx做反向代理就没有问题了。

但是,我还是想搞清楚,到底是那里出了问题?

解决了问题,说明我写的代码没有问题,而是Golang本身在监听http请求的时候,处理的不干净。 不过用Nginx做反向代理,Golang一样也需要监听http请求,区别是port换了,然后请求来自本地物理机器。

这难道就是原因?希望有高人指点。

# 6

rn2dy

无代码,无真相

# 7

qkevin123

@rn2dy:

我的go代码,自己写的,2M,没法贴的,只能在这里说说方法。

# 8