昨天VPS突然挂掉了。我晚上玩推特时才发现(choqok更新不到数据了)。不过浏览器Opera里的twitter.com代理还能用,于是我就没管,以为是网络连接问题。
不过睡前看告警邮件,发现全系列的网络访问都不能进行,PING也失败,开始怀疑VPS死机了。。。
今早起来,在Control Panel上看VPS上的状态,提示的还是绿色的“Online”(你妹的,后来发现只要电源开着就算是Online!),但显然SSH已经无法连接上去了。
场景介绍完毕,顺便讲述背景
我的VPS是这款 Hostigation 上的KVM 128m,前几天买着玩,发现网络很好(什么pr路线啥的我也不懂),访问速度比之前的directspace快一些些(对于我这种被教育网毒害若干年的,内心一直怀着对网速的渴望)。这个KVM机器后台有个VNC登录界面,是Java Applet,于是捣鼓了一下(顺便吐槽一下openjdk-plugin,弱爆了),成功登录机器——结果看到界面后我惊呆了:

内存用完了啊亲!久违的Kernel Panic啊亲!!我第一次知道内存爆掉会连着内核也爆啊!!吐槽不能……只能默默的点击页面上的Reboot按钮……
深入内核被爆的秘密
其实内存不足的原因我也能大概猜到,机器上跑的是nginx + php5-fpm + wordpress。fpm这货根本就是内存大户,VPS上又只有128M内存+256M Swap,Wordpress博客又慢又胖,VPS上的CPU又不给力,监控宝还在其他地方默默地发起请求访问博客首页……所以访问不能承受之重,VPS内存溢出了。
为了验证,我祭出压力测试工具ab2(就是apache带的工具),首先小试一招:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| $ ab2 http://banjuan.net/blog/
……
Total transferred: 25862 bytes
HTML transferred: 25642 bytes
Requests per second: 0.48 [#/sec] (mean)
Time per request: 2075.089 [ms] (mean)
Time per request: 2075.089 [ms] (mean, across all concurrent requests)
Transfer rate: 12.17 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 196 196 0.0 196 196
Processing: 1879 1879 0.0 1879 1879
Waiting: 1457 1457 0.0 1457 1457
Total: 2075 2075 0.0 2075 2075 |
悲催地看到,请求处理时间为1879ms。。。接近两秒啊!而从后台top命令可以看到 [php-fpm: pool www]这个进程突然冒出来,然后吃住20M内存不动了。。。
再来一次强大的招式,每秒并发10个请求,一共请求100次,看看啥情况:
1 2 3 4
| $ ab2 -n 100 -c 10 http://banjuan.net/blog/
...
apr_poll: The timeout specified has expired (70007)
Total of 3 requests completed |
偶也,跑了一分钟后突然来了一句超时,压力测试工具自动停了。这时候VPS上的悲惨状况我就不截图了(当时也没截图),内存已经彻底不够用,256M SWAP都快分配完毕了,幸好在悲剧重演之前,ab2工具自己停掉了,呼!看着岌岌可危的VPS,看着进程列表中满眼的 php-fpm,我只好默默地把他们都重启掉。。。
娇小的VPS果然不能承受野蛮的访问
研究出是php5-fpm的问题后,那就容易办了。按每个fpm进程20M内存占用来算,VPS上最多只应该启动5个进程;另外考虑到咱的博客基本没访问量,所以空闲fpm进程就设置为少一些吧。另外,也限制一下请求处理的时间,避免排队排到死:
1 2 3 4 5
| pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 2
request_terminate_timeout = 15 |
这一次,再跑ab2压力测试工具,总算能够活下来了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| $ ab2 -n 100 -c 10 http://banjuan.net/blog/
……
Concurrency Level: 10
Time taken for tests: 453.626 seconds
Complete requests: 100
Failed requests: 44
(Connect: 0, Receive: 0, Length: 44, Exceptions: 0)
Write errors: 0
Non-2xx responses: 34
Total transferred: 1582999 bytes
HTML transferred: 1563330 bytes
Requests per second: 0.22 [#/sec] (mean)
Time per request: 45362.583 [ms] (mean)
Time per request: 4536.258 [ms] (mean, across all concurrent requests)
Transfer rate: 3.41 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 196 202 3.9 201 219
Processing: 1943 43170 13715.5 46237 63341
Waiting: 1524 37434 13529.3 37333 60571
Total: 2142 43372 13715.4 46435 63540
Percentage of the requests served within a certain time (ms)
50% 46435
66% 52552
75% 54373
80% 56466
90% 58586
95% 60083
98% 60781
99% 63540
100% 63540 (longest request) |
不过,悲惨地看到请求时延平均增长到了6秒。。。可见排队之长。。。
请求量之禅
这一次的事件告一段落了。不过有关这个请求量、处理时间的数值却引起我的思考。
目前这个弱小的kvm虚拟机,良好情况下,一个请求要消耗 2s,进程数限制是最多 5 个进程,这样所能承受的每秒最大请求是 2.5 r/s 。真是一个微小的数字。。。
在我的实际工作中,公司里的WEB机器跑的还是古老的C++写的CGI,一般单个CGI进程承受的访问量是 10r/s ~ 20r/s,机器配置是酷睿CPU+8G内存,一般CGI开50个进程(还同时跑着其他CGI),单机CGI承受量为500r/s(目前最高的我见过有1600r/s)。这时机器负载还算是正常服务,性能消耗还留有余地,一般CPU占用为30%,负载小于1,能再承受50%的高峰访问。
或许会问,有必要追求这个高的访问承受力吗??实际上,我们公司的CGI部署起来,很少只用1台机器就够的。多数情况下,需要用4台以上(刚才提到的那个1600r/s的CGI),有些极高访问量的CGI会有每秒1万次请求,如果单机以 500r/s算,那么需要20台服务器组成集群来处理。而这些机器还只是专门跑WEB服务器的,DB还是另外独立部署,所以后面还有一大堆的DB机器……这些都是赤裸裸的钱啊……
所以,VPS什么的,真的是只能玩玩,搭个没访问量的个人博客。弱爆了唉。。。
vps, 访问量