golang 进程出现too many open files的排查过程

1. 现象

服务的cpu跑满(golang实现),并大量报too many open files错误.服务使用systemd来运行,部署在阿里ecs上.


2.分析

从日志来看,cpu的上升主要为到达文件数限制引起的,但之前已经更改过系统的文件数及所有用户文件数,按道理是不应该出现这个问题的,后来查阅资料发现,文件数可以从三个维度限制分别为操作系统限制,用户态限制,以及进程限制,对于这三个维度选取最小值生效.于是对系统进行分析.


首先查看当前打开文件数,进程占用的文件数并不多.

lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more

然后获取系统级文件数限制

输入命令

cat /etc/sysctl.conf

得到

fs.file-max = 1000000


查询用户文件数限制

cat /etc/security/limits.conf

得到

* soft nofile 655350

* hard nofile 655350


单独获取程序文件数限制(9928为进程id)

cat /proc/9928/limits

得到

Max open files 1024 4096 files

如上可以发现,虽然系统及用户文件数调大了,但是程序的仍然是一个很低的值,这里进程的文件数一般情况下是认继承用户级的值的,而这里却没有继承,一开始怀疑是systemd启动的问题,但是手写了另外一个测试服务,发现该服务又继承了用户文件数.

百思不得其解的情况下在systemd的启动脚本里加了文件数的初始化值.

如下:

[Service]

Type=simple

LimitNOFILE=40960

LimitNPROC=40960

单独获取程序(9928为进程id)

cat /proc/9928/limits

得到

Max open files 40960 40960 files


发现文件数被设置成了启动时的初始化值.至于为什么没有继承用户级的值,怀疑是程序里做了参数设置,这里如果有人知道golang里具体情况的话,还望不吝赐教.


3. 总结

归结来说出现文件描述符的错误的排查步骤如下:

首先,判断配置参数是否正确,这里涉及到对上面提到的三个维度的检查,特别时进程维度的,如果只是ulimit -n 一下就完事了,那估计旧要像我一样进坑了.

如果参数都正确,那么查看一下当前系统被使用了多少文件数,如果使用的确实多,那要看一下使用在什么地方,这里一般有两种情况,大量连接未关闭,或者大量读文件的句柄未关闭.具体原因相信到这里就可以排查出来了.

相关文章

什么是Go的接口? 接口可以说是一种类型,可以粗略的理解为他...
1、Golang指针 在介绍Golang指针隐式间接引用前,先简单说下...
1、概述 1.1 Protocol buffers定义 Protocol buffe...
判断文件是否存在,需要用到"os"包中的两个函数: os.Stat(...
1、编译环境 OS :Loongnix-Server Linux release 8.3 CPU指...
1、概述 Golang是一种强类型语言,虽然在代码中经常看到i:=1...