/ tornado

nginx 499 Recv-Q

不知道标题应该怎么写才可以描述清楚这个问题。我们有一个服务,提供一些数据给自己用,后端连着Oracle和MSSQL数据库,由Nginx作为反向代理,Tornado作为后端服务查询写入数据。

一开始记得是开了8个Tornado进程,运行了挺长时间没发现问题,最近发现在调用接口是经常得到status code 499,这不是标准的code,而是nginx自己用的,用来表示客户端主动断开连接的状况。客户端在我们这里其实是python的requests库,比如我们需要刷新会员积分,会用requests请求接口,获得会员积分信息,调用时在requests的timeout参数中加入连接超时和读超时限制,一般连接超时设置到3.05s,读超时设置到27s。一般出现499时都是read timeout。

一开始我以为是8个Tornado不够,导致大量请求挤压在那里,超过27s,客户端断开。于是我增加一倍的Tornado进程,发现竟然没问题。后来我又增加到20个Tornado进程,不过实际根本不需要这样做,因为后来,在20个进程的情况下,依然出现大量499。

登陆到服务器上后,用netstat看了一下tcp连接情况,有很多连接状态是CLOSE_WAIT,并且Recv-Q基本都不为0,如果重启一下Tornado,一切又恢复正常,应该又可以用十几天。这个服务中途不会重启,这次遇到问题后我看了下这些进程都运行了12天,或许每天深夜重启一下是个很好的办法,但我仍想知道到底是怎么导致这样的结果。

因为这个接口都是我们自己调用,而且调用量大不到哪去,按理说4个Tornado+Nginx足够应对,暂时没有更具体的信息支持我继续研究,现在我减少Tornado进程到4个,过几天再看看效果。

最近又出现过几次499。这次梳理了一下,出现499是因为客户端(requests库)认为等了很久都没得到响应,超过了自己设定的timeout就主动断开了,nginx作为中间人当然知道,因为nginx一边接着客户端的请求,一边找后端要响应,现在客户端要求断开,nginx把499写到了日志中,此时,nginx应该让后端别继续做了,因为你即便得到结果,客户端也断开了,所以你(后端)还是干点别的去吧。

最近出现499都是调用某个特定方法时,超时,之后就会频繁出现499,目前做法是把这个方法的结果缓存了(在redis中),每次都从缓存中读取,定期再刷新缓存,过一阵子看看还会不会有问题。

过了一阵子,没出现问题,看来确实是这个方法导致的。这个方法需要连接SQL Server查询一些信息,估计是使用的python库(freetds和pymssql)不够好?