运维 [已解决] 服务器各项资源都空闲但还是有请求拥塞

birbird · 2015年10月25日 · 最后由 birbird 回复于 2015年10月28日 · 8291 次阅读

我这是个 ruby 小项目,就看成个代理吧,接受来自客户端(60 - 100 个)的请求,收到客户端请求后,去访问一些远端服务,得到数据,写数据库(Mongodb),再返回给客户端。有点特别的是,客户端会一个接一个不停地发请求。

4 核 8 G 的机器,Passenger Standalone 部署,开了 24 个进程。 大部分时候服务还是工作的很好的,响应及时,Requests in queue 为 0。 但是,偶尔,不是经常,Requests in queue 里会有几十上百个请求,这时候服务器响应也很慢,十秒以上。 这时,从 passenger-status 看,进程有富余,不是所有进程都是满负荷工作。 从云主机控制台监控以及 top,free 看,各项资源(CPU,内存,带宽)都有富余,都没有用满。

请问这该怎么查呢? 任何帮助,不甚感激!

你的代理依赖其他什么应用么?比如访问数据库什么的。排除了外部依赖的瓶颈后,我假设你的代理程序是不是一个 socket server,如果是的,用 lsof 命令检查一下是不是达到了最大打开文件数,如果是的话,首先要解决的问题还是要及时断开连接才行。 还可以通过设置允许重用 time_wait 状态连接提高性能,就是 net.ipv4.tcp_tw_resuse 和_recycle 那两个参数。

如果都不能解决问题,不妨看看/var/log/message 看看 syslog 有没有什么有价值的信息,主要这种问题信息量太少,只能不断试错。

希望你解决问题后分享一下原因和解决方案,谢谢

oneapm newrelic 添加上看看效果。

收到客户端请求后,去访问一些远端服务,得到数据,写数据库。

很有可能 external request 把你的 web server 的进程 block 住了。

你换成 puma 会好一些。(最多阻塞一个线程,而不是一个进程)

收到客户端请求后,去访问一些远端服务时,远端服务会 block 吧?

#1 楼 @cicero 十分感谢你这么详细的指导哈,可能是我没说清楚,我这应用全在 http 上的,不是 socket server,进来出去的都是 http request。

中转代理应该用事件式编程吧,例如 https://github.com/eventmachine/eventmachine ,然后 Nginx 代理到 eventmathin server 上。一般的 ruby 脚本和 Passenger 基于进程和线程是顺序式的,访问外部资源时会阻塞。

#3 楼 @xiaoronglv #4 楼 @sevk 我也怀疑过是不是被远端 block 了。 但如果是这样,现象不应该是 24 个 ruby 进程被占满么。但实际情况是,没有用尽 24 个进程,明明有空闲的进程,就是不往里面派,堵在 Requests in queue 里。 而且还有一个现象,就是我这个服务里还有一些不依赖远端服务的接口,这些接口就是简单做个数据库查询就返回了,在服务器响应慢的时候,这些接口也慢。

所有的远端请求都有日志,从日志来看,没有明显的慢,所以我觉得不像是远端问题,或者,如果要确定是远端慢,应该从哪儿分析呢?

#3 楼 @xiaoronglv #6 楼 @rei 麻烦请问,我是这么理解的,你们看有问题么 我这 ruby 程序不同之处就是处理一个请求时间略长,那我们简化一下,就是一个请求进来等十秒,然后返回。 然后假设我机器够好,开 60 个 ruby 进程,60 个客户端,每个都能分到一个进程。60 个并发对 nginx 来说毛毛雨,随便搞。 这样每一个进来的请求都应该能立即得到处理,不应该堵在队列里。

请问我这个理解有问题么?

#8 楼 @birbird 外部请求有没有限时?没有的话卡住一个这个进程就废了,然后客户端重试……

update:不过 Passenger 默认好像对整个请求有限时。

#9 楼 @rei 刚才又来了一下,不过一会他就自己恢复了,见后图。 我觉得你这分析靠谱,也许我那 24 个进程被废了好多,实际就几个进程有用,那就能解释这个现象了,十分感谢!

总结,从 passenger-status 的输出其实是可以看出问题来的,我之前没有搞清楚每个数据的含义,Sessions 这个数据可以说明进程忙闲程度。详见 https://www.phusionpassenger.com/library/admin/standalone/overall_status_report.html#dealing-with-common-request-related-problems

简单来说,我这问题就是处理一个请求的时间可长可短,当意外发生时,进程被占住的时间太长(比如一分钟),进程就会不够用了,就会出现大部分时候没问题,偶尔出问题的情况。

这种 IO 密集的应用应该用事件驱动的方式编程,我打算换 https://github.com/eventmachine/eventmachine 了。 谢谢各位。

#3 楼 @xiaoronglv 我换 puma 试了一下,感觉更慢啊,日志都翻得很慢,像跑不动的样子。

第一次用,就配了最简单的几项,puma.rb 是这样的

environment 'production'
threads 256, 256
port 8080

bundle exec puma 启动的,启动的输出是正常的,资源占用是下去了,但效果还没有 Passenger 好。 请问我哪里配错了么?

因为你有第三方请求,所以可以看一下连接数

ulimit -n

再看看 TCP 的连接数

netstat -nap | grep tcp |wc -l

#12 楼 @birbird

你的线程数配的太多了,额外增加了很多线程切换的开销。假如你的机器是 4 核,可以这样配置:4 个进程 x 16 个线程。

PS: Puma 每个进程 130M 左右,4 个进程的内存开销不会超过 1G。

#13 楼 @azhao 谢谢 ulimit -n 是 1000000 netstat -nap | grep tcp |wc -l 是 9051 这应该就是没问题吧

#14 楼 @xiaoronglv 谢谢啊 4 × 16 还是处理不过来呢,还是要换编程方式

需要 登录 后方可回复, 如果你还没有账号请 注册新账号