项目使用的是django,使用了gunicorn作为动态web服务,使用的是supervisor作为进程管理工具。
由于特殊原因,最近上线了一个非常耗时的http接口,一段时间后开始有用户陆续反馈他们的代码调用这个接口会返回502错误,经过一段时间的排查排除了网关的问题,确认是系统问题。
经过日志信息的比对分析,发现这个接口请求的代码只执行了大半,没有执行完。怀疑是worker进程被强制重启,但是没有证据,于是在日志中加上了进程号信息,最终排查发现这个接口的处理进程确实在某一个时间点之后开始就完全没有日志了(也就是说进程确实被重启了)
一开始以为是supervisor强制重启了进程,但是看到supervisor配置的等待时间是1个小时,但是这个接口的耗时远没有1个小时这么久,所以排除了supervisor问题。
结合日志和代码发现:每次接口请求都是在同一行代码上出现问题。代码本身没什么疑点,但这行代码使用的第三方的sdk,肝了源码发现这个函数会阻塞整个进程,但也不会导致内存溢出等问题,代码问题的排查实在没有头绪。但柯南说过:“排除了所有可能之后,最不可能的那个可能就是真相”,那怀疑对象就落在了gunicorn身上。
上网查吧,查到gunicorn有个参数叫timeout,是这么描述这个参数的
gunicorn默认的timeout时间是30秒。 gunicorn的管理进程如果在timeout时间内,没有收到worker进程的消息心跳,则会认为worker进程出现了死亡,从而重启相应的worker进程。会导致worker进程正在执行的任务被中断。 worker进程处于阻塞或高CPU计算时,会出现不能及时发送心跳给管理进程的问题。
好了,大概率抓到问题点了,我的配置参数里面没有设置这个参数,也就是说使用的默认30秒,但刚刚上面提到的那行阻塞代码的阻塞时间完全在30秒以上,那这个问题也就明朗了。把timeout参数加上吧。
疑点:
目前遗留了一个问题,这个进程管理用心跳感觉不太合理,实在不清楚是如何设计的,回头再肝一下gunicorn的源码吧
标签:gunicorn,代码,worker,接口,django,timeout,进程,客户端 From: https://www.cnblogs.com/gangdou/p/17514020.html