go语言 socket: too many open files 错误分析

问题背景:

近期针对老的PHP接口做了迁移重构,用golang重新实现,在上线之前,测试进行了压测,压测的量级为:200请求/s, 连续请求10s,发现接口出现大量超时错误,查看日志发现错误信息为:socket: too many open files (测试服务器配置:4核8G)

问题分析:

出现问题后,心里大概猜测是新版go接口使用了大量协程并发的去调用其他服务获取数据,导致一瞬间将socket链接数占满导致的

首先查看了系统的文件描述符打开限制, 为65535:

 然后让测试帮忙重新压测,查看项目进程使用的文件描述符数量:

go语言 socket: too many open files 错误分析_第1张图片

发现并没有达到系统限制 

然后百度进行查询,才知道每个进程有自己的文件描述限制,查看方式如下:

cat /proc/839357/limits

go语言 socket: too many open files 错误分析_第2张图片

 可以看到,当前项目进程的文件描述限制为 1024, 那到这里,一下就明朗了,确实是文件描述符不够用导致的

那么问题来了,这个进程的文件描述符石谁来控制的呢,我想到我们的go服务使用守护进程来进行统一管理的,百度查询后了解到,守护进程有一个默认的文件描述符配置,初始值为1024,不做修改的话,守护进程启动的每个服务,文件描述限制都是1024,如下图:

go语言 socket: too many open files 错误分析_第3张图片

问题解决:

 为了临时解决此问题,决定修改为65535,发现改了配置之后,reload、update都不生效,必须重启守护进程,这里要特别注意

因为线上守护进程不能随意重启,所以通过代码修改了此配置,代码如下:

syscall.Setrlimit(syscall.RLIMIT_NOFILE, &syscall.Rlimit{
		Max: 65535,
		Cur: 65535,
})

至此,这个问题算是临时解决,可以正常上线

深层次思考:

通过这个问题,可以看出系统本身的抗并发能力很弱,所以上线后又进行一次具体的分析,分析思路如下:

  • 模拟压测请求,查看并发情况下,开启的协程数量 (基本协程的使用都是请求其他服务的接口,通过这个来看对其他服务的并发调用情况)
  • 查看依赖服务主要接口的抗并发能力,在并发量大的情况下,依赖服务是否存在问题从而影响web端
  • 调用其他服务是否使用了连接池,tcp是否进行了复用,链接是否正常关闭
  • 调用其他服务是否有做超时熔断以此来保证当前服务的稳定性
  • 当前服务是否有做限流控制,当并发超过承受能力后,新的流量只会机器压力更大导致服务出现更多的问题
  • 对携程的使用是否要加以控制,比如使用协程池

go萌新一枚,后续的线上问题以及解决过程会持续更新

下篇文章会针对各项思考去逐个分析

你可能感兴趣的:(golang,开发语言,后端)