Golang 服务之坑:too many open files

出现这个问题是因为服务的文件句柄超出系统限制。当Go服务程序出现这个问题,首先应该看系统设置,然后再看程序本身。

too many open files

大量的 accept4 错误

1
2
http: Accept error: accept tcp [::]:8080: accept4: too many open files; retrying in 1s
http: Accept error: accept tcp [::]:443: accept4: too many open files; retrying in 1s

系统设置

首先查看系统

1
ulimit -n

默认是 1024 ,要改大一些。

1
ulimit -n 524288

这是临时的修改,要永久的修改,可修改文件 /etc/security/limits.conf 参见

看系统之后还要看你的程序的句柄限制,因为你的程序部署问题,系统设置修改了,但程序的设置还没变。可以使用下面命令行查看程序的限制

1
cat /proc/{your_app_pid}/limits

结果可能类似这样:

设置ulimit

上图的 Solft Limit 还是 1024,我用的是 supervisor ,必须重启 supervisor。重启后参数如下图:

设置ulimit

注意 这里重启不能用系统自带的,如:

Bash:
1
/etc/init.d/supervisor restart

否则还是 Max open files 1024 ,要先 kill 掉 /usr/bin/python2 /usr/bin/supervisord 的进程,然后运行

Bash:
1
2
3
supervisord
or
/usr/bin/supervisord -c /etc/supervisor/supervisord.conf

更新

如果使用系统的服务重启 supervisor ,则仍然没生效,解决办法:

  • 打开文件 /etc/systemd/system.conf
  • 修改两行
    • DefaultLimitNOFILE=1048576:2097152
    • DefaultLimitNPROC=262144:524288
  • 实行命令 systemctl daemon-reexec
  • 退出重新登录
  • systemctl restart supervisor.service
  • cat /proc/[pid]/limits 看看

就是这结果

plaintext: limits
1
2
3
Max processes             262144               524288               processes 
Max open files            1048576              1048576              files     

程序设置

如果不注意,代码里可能存在一些连接泄漏。常见的泄漏是在 http.Response 调用之后忘记调用 resp.Body.Close(),或者是放置位置不对。

空闲连接可能是另一个可能的原因。 默认情况下,会使用缓存来重用连接。访问许多主机时,这可能会留下许多打开的连接。 可以使用 TransportCloseIdleConnections 方法以及MaxIdleConnsPerHostDisableKeepAlives 字段来管理此行为。

如果是这种情况,可以尝试在传输句柄上显式调用 CloseIdleConnections 或减小MaxIdleConnsPerHost 的值。

还应该在 http server/client 添加超时机制来避免连接泄漏,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
srv := &http.Server{
    ReadTimeout:  5 * time.Second,
    WriteTimeout: 10 * time.Second,
    IdleTimeout:  120 * time.Second,
    TLSConfig:    tlsConfig,
    Handler:      serveMux,
}

var tr = &http.Transport{
		TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
		TLSHandshakeTimeout:   5 * time.Second,
		ResponseHeaderTimeout: 10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}
var httpClient = &http.Client{
		Timeout:   time.Second * 30,
		Transport: tr,
	}

下面的命令可以让你判断是不是连接池中的连接有没有正确关闭:

1
2
3
4
5
6
7
# cat /proc/19213/net/sockstat
sockets: used 109
TCP: inuse 4 orphan 0 tw 14 alloc 9 mem 2
UDP: inuse 5 mem 16
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0

如果 TCP inuse 很大,就很有可能是连接没有正确关闭。

本文网址: https://pylist.com/topic/201.html 转摘请注明来源

Suggested Topics

Tornado 搭建基于 WebSocket 的聊天服务

这年头 Python web 框架是有点泛滥了. 下面要介绍的是 facebook 的开源框架 tornado. 这东西比较简单, 而且自带 WebSocket 支持, 可以用它做个简单的聊天室. ...

在 Nginx 和 Golang web 上抢先体验 QUIC

QUIC(Quick UDP Internet Connection)是谷歌推出的一套基于 UDP 的传输协议,它实现了 TCP + HTTPS + HTTP/2 的功能,目的是保证可靠性的同时降低网络延迟。QUIC 是使用 UDP 协议,可以与原来的 TCP 服务不冲突。...

Golang结合OpenCC实现高效的中文简体繁体互转

之前在页面中使用简体转繁体的功能一般是使用JS对页面进行字典替换,这样可以解决大部分问题,但要进行精确的转换,才发现简繁体的转换是个复杂的过程。幸好有个非常棒的繁体转简体开源项目OpenCC可以很好的工作。...

一个简单高效的LRU 缓存,golang 实现

LRU(Least recently used,最近最少使用)是根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。...

Golang 实现新闻网页提取正文内容

前段时间接触到新闻页面的提取问题,发现了python 实现的 gne ,测试一段时间,效果很好,但还不适合个人的需求,于是就用 go 来实现类似的功能。...

Golang 版 supervisord 使用记录

python 版经常出现一些错误,比如 supervisor.sock 文件找不到的错误。懒得去整,试试二进制的 supervisord ,用 Go 语言编写。...

使用Golang selenium WebDriver 自动登录微博

有时候在Golang 程序里需要读取微博的某个页面内容,提示需要登录。最简单的方法是在浏览器里登录后,直接复制Cookie 的内容,然后 http 请求带上Cookie。这样会有人工介入,不是很方便,这里借用 selenium WebDriver 来打开微博登录页面,然后自动填入用户名与密码。...

Leave a Comment

1 thoughts on "Golang 服务之坑:too many open files"

#1 孟先生 says:

你好,我是 pylists.com云课堂系统的独立开发者,想购买你的域名 pylist.com,不知道你是否可以转让给我,我买域名之前一直没有联系到你。