起源
星期天晚上,我正美滋滋的躺在床上刷小破站,跟徐云流一起浪中国,看着巍峨的昆仑山,正在思考里面有没有住着旧日支配者。。。猝不及防一个电话,喂喂喂,线上服务出问题了,赶紧看一下!!!
唉,脑海中瞬间一万头喜羊羊奔腾而过,虽然在休息日我一向不看消息,但是电话打过来了也没办法,还是看一下吧。
先稳住服务
据描述,公司OP大佬在观察监控时发现线上某node服务进程句柄数一直升高,存在资源泄漏问题,需要安排重启,于是幸运的找到了今晚值班的我(其实我是个菜🐔,人大佬说重启那就重启呗)。
先把服务稳住再说,大半夜十一二点下床把电脑铺开,新拉个分支上线,一通猛如虎的操作过后,服务重启,句柄数总算是降下来了。开开心心滚去睡觉。
找找原因
周一的早晨,总是莫名的不想上班,去了公司领导说排查一下原因吧,我说好(bu)的(hui),打开线上的监控看了看,WTF?句柄数还在稳步上升。。
那就看看具体什么原因吧,领导交代的任务哪有完不成的道理。
首先申请了一台线上机器的权限,看看究竟是哪些进程的句柄在升高,在linux下,我们使用 ulimit -n 指令可以查看到单个进程可以打开的最大文件句柄数,系统默认值1024。
由于知晓此线上服务是node服务,所以我直接查询了node进程的pid,使用如下命令:
pgrep -l node
一个很简单的命令,pgrep,可以迅速定位包含某个关键字的进程的pid,-l参数,可以显示出pid及进程名字;不加-l只显示pid。
PS: 使用如下命令可以统计当前进程打开的句柄数,如果存在此问题,可以看到某个进程打开的句柄数一直在上升。
lsof -n| awk '{print $2}'| sort| uniq -c| sort -nr| more
然后使用 ps -aux | grep <pid> 可以看到是哪个进程
执行此命令需要root权限,由于是线上机器,OP给我开不了root权限,以下是在联调机器上运行的效果
然后根据此pid,查看重启后进程的文件打开数,使用如下命令:
lsof -p <pid> | wc -l
可以看到打开的文件数,每秒都在稳步上升,已经快逼近极限了,使用lsof -p <pid>就可以看到它究竟打开了些什么文件
好家伙,一兜子全是log文件,滚了十秒停不下来!!!
至此,终于知道了打开的文件是什么了,那就好整了,去代码里定位原因吧。
在代码库中搜索文件关键词发现,这是一个埋点的方法,用的是第三方的神策SDK
调了它的track方法之后就出现了这个问题
复现
基于这是一个已经存在于线上的问题,那么找一个环境直接把master代码布上去应该就可以复现,于是接下来就是申请环境、拉分支、布代码、上机器观察一系列常规操作。
随便进一个有埋点的页面,然后看一下当前node进程打开的文件句柄数
多点击几次有埋点的地方,然后再看一下
嗯 确实增多了!!!看一下打开的文件是不是上面的log文件
是它,成功复现。
解决
那就找找解决办法吧,上github翻了一下sdk的源码,找到一个close方法,应该就是关闭文件句柄的方法,放在代码里试一下
再点几下埋点看看打开的的文件句柄数
OK,确实是不增加了,一行代码的事儿,问题解决,封版提测!
写在最后
通过这个问题可以看出,如果句柄一直不关掉,会造成资源泄漏,导致系统性能降低,而且会导致程序出错。千里之堤,溃于蚁穴,广大厂友们写代码时还是要注意啊。不说了,去搬砖了