Ruby on Rails以优雅的MVC架构闻名。这个架构如此诱人和美丽,我也是向往已久。近日正在为射手的一个新应用做系统选型,不由自主的想结束传统php的砖头式开发,而开始转向MVC架构。于是有了Rails和CakePHP 2个候选人。
不过我一直担心的是性能和部署问题。这2个话题在网上众说纷纭,很少见到客观而有说服力的论证和充分模拟实际环境下的压力测评。作为架构选型的重要决定,我们既不能人云亦云,更不可凭空臆想,一定要有充分的测试数据才能帮助做出正确的决定。
心动不如行动,立刻着手安排了仿真环境测试。第一步是设计测试方案:
压力测试的目标集中在RoR和CakePHP的效率,所以采用同样的 nginx 生产环境,但避开所有数据库操作以避免瓶颈转嫁到数据库影响结果。
代码的主要部分都是通过输出128000个4位的十进制随机数,来模拟总计约500KB的页面数据输出。调用的指令都很基本,对脚本测试来说很公平。
不过既然是虚拟高压力测试,实际环境中数据库读写等操作的时间开销应该有一个仿真替代,所以通过 Sleep 200ms 来仿真具有高度数据压力的服务端。当然我们都知道 Sleep 是没有真实的cpu开销的,所以不会影响测试结果的公平。
测试工具使用经典的ApacheBench。先后测试10并发100请求(-c 10 -n 100) 的中等压力,和200并发5000请求(-c 200 -n 5000)高压测试。
跳往结论
环境
- OS: FreeBSD 8.1
- CPU: Intel 4核心 Core 2
- RAM: 4GB 内存
- PHP环境:nginx+php-fpm(5.3.3)+APC
- Rails环境:nginx+passenger+Ruby(1.8.7) on Rails(3.0.0)
所有软件均使用ports安装fpm的优化配置:
以下是引用片段: pm.max_children = 1000 pm.start_servers = 20 pm.min_spare_servers = 5 pm.max_spare_servers = 1000passenger的优化配置(nginx.conf) passenger_max_pool_size 300;//4GB内存最大的允许值,再追加便无法启动passenger 通过 Rails 脚本创建 Test App. |
rails new dummyRub on Rails代码:
以下是引用片段: // app/controller/test_controller.rb class TestController < ApplicationController def index sleep(0.2) end end// app/views/test/index.html.rb <% 128000.times do %><%=rand(8999)+1000%><% end %>php 代码: // vsruby.php <?php usleep(200000); echo “<html><head></head><body>”; for($i = 0; $i < 128000;$i++) { echo mt_rand(8999,9999); } echo “</body></html>”; |
CakePHP代码:
以下是引用片段: // CakePHP // app/controller/test_controller.php <?php class TestController extends AppController { var $name = ‘Test’; function index() { usleep(200000); } } // CakePHP // app/views/test/index.ctp <?php for($i = 0; $i < 128000;$i++) { echo mt_rand(8999,9999); } ?> |
10并发100个请求
以下是引用片段: // Ruby on Rails // CPU usage: 100% Server Software: nginx/0.8.52 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /test/ Document Length: 512731 bytes Concurrency Level: 10 Time taken for tests: 40.939 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 51334500 bytes HTML transferred: 51273100 bytes Requests per second: 2.44 [#/sec] (mean) Time per request: 4093.898 [ms] (mean) Time per request: 409.390 [ms] (mean, across all concurrent requests) Transfer rate: 1224.54 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.0 0 0 Processing: 1231 4036 3167.1 3149 16396 Waiting: 1203 2428 2533.7 1625 15683 Total: 1231 4036 3167.1 3150 16396 Percentage of the requests served within a certain time (ms) 50% 3150 66% 3353 75% 3679 80% 3893 90% 12307 95% 12307 98% 16108 99% 16396 100% 16396 (longest request)//php //CPU usage: 20-30% Server Software: nginx/0.8.52 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /php/ Document Length: 512039 bytes Concurrency Level: 10 Time taken for tests: 4.144 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 51218600 bytes HTML transferred: 51203900 bytes Requests per second: 24.13 [#/sec] (mean) Time per request: 414.389 [ms] (mean) Time per request: 41.439 [ms] (mean, across all concurrent requests) Transfer rate: 12070.36 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 0 Processing: 400 405 14.0 403 502 Waiting: 201 205 3.1 204 218 Total: 400 405 14.0 403 502 Percentage of the requests served within a certain time (ms) 50% 403 66% 404 75% 405 80% 405 90% 408 95% 409 98% 501 99% 502 100% 502 (longest request)// CakePHP Server Software: nginx/0.8.52 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /cakephp/ Document Length: 512652 bytes Concurrency Level: 10 Time taken for tests: 4.036 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 51291900 bytes HTML transferred: 51265200 bytes Requests per second: 24.78 [#/sec] (mean) Time per request: 403.553 [ms] (mean) Time per request: 40.355 [ms] (mean, across all concurrent requests) Transfer rate: 12412.20 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.7 0 6 Processing: 302 399 119.1 363 775 Waiting: 275 370 119.9 340 764 Total: 302 400 119.1 364 775 Percentage of the requests served within a certain time (ms) 50% 364 66% 372 75% 378 80% 381 90% 725 95% 755 98% 775 99% 775 100% 775 (longest request) |
5000个请求,200并发数
以下是引用片段: // php Server Software: nginx/0.8.52 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /php/ Document Length: 512039 bytes Concurrency Level: 200 Time taken for tests: 82.243 seconds Complete requests: 5000 Failed requests: 0 Write errors: 0 Total transferred: 2560930000 bytes HTML transferred: 2560195000 bytes Requests per second: 60.80 [#/sec] (mean) Time per request: 3289.722 [ms] (mean) Time per request: 16.449 [ms] (mean, across all concurrent requests) Transfer rate: 30408.75 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 1 1.6 0 20 Processing: 405 3258 4830.3 2675 56787 Waiting: 202 1048 1324.8 344 53432 Total: 405 3259 4830.3 2676 56787 Percentage of the requests served within a certain time (ms) 50% 2676 66% 3081 75% 3361 80% 3535 90% 3828 95% 4262 98% 5709 99% 31863 100% 56787 (longest request) // CakePHP Server Software: nginx/0.8.52 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /cakephp/ Document Length: 512652 bytes Concurrency Level: 200 Time taken for tests: 99.652 seconds Complete requests: 5000 Failed requests: 0 Write errors: 0 Total transferred: 2565102923 bytes HTML transferred: 2563767656 bytes Requests per second: 50.17 [#/sec] (mean) Time per request: 3986.073 [ms] (mean) Time per request: 19.930 [ms] (mean, across all concurrent requests) Transfer rate: 25137.36 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 4 57.8 0 1663 Processing: 367 3969 1825.7 3857 10630 Waiting: 280 1543 731.9 1297 3953 Total: 472 3973 1824.8 3860 10630 Percentage of the requests served within a certain time (ms) 50% 3860 66% 4466 75% 5065 80% 5426 90% 6482 95% 7337 98% 8599 99% 8847 100% 10630 (longest request)// Rails |
约10分钟后,服务器进入假死状态。
备注:
因为不太相信ruby的性能会有这样大的差距,怀疑是否ruby的rand()效率格外的低造成问题,我在测试完成又将rand()去掉,改为直接输出数字,但脚本执行时间并没有明显缩短。所以应该说是 ruby 对循环或数据输出的处理效率不佳导致。
结论:
坦白说,几个ab测试跑下来,ruby的成绩如此之差,不但10并发的100请求就已经用满了服务器资源,更甚至没有能通过200并发5000请求的高压测试,这把我自己也吓了一跳。想到坚持在使用rails的twitter,心中的敬佩油然而生。不知道那是什么样的硬件或软件优化,才可以用ruby来支撑那样巨大的访问量(希望这个问题能引出高手来回答)。
客观的从纯性能的角度出发,在生产环境中,Ruby/Rails还是只适合Small Business。对与压力较高的服务或应用,就必须投入大量额外的硬件资源才能维持。本次测试中,RoR与CakePHP的性能差距达到10倍之多,实在让我不敢考虑把Rails用在生产环境中。另一方面,php依托庞大的社区,多年来积累了众多的优化手段,其性能领先也有它的道理。在php架构之上的MVC候选人CakePHP,性能虽然相对于传统php的代码书写方法略有损失,但这个损失不到10%。所以对于在考虑MVC架构的php用户来说,CakePHP 的性能完全在可以接受的范围内。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
作者
相关推荐
-
私人定制:十款最佳Node.js MVC框架
Node.js是JavaScript中最为流行的框架之一,易于创建可扩展的Web应用。本文分享十款最佳的JavaScript框架。
-
Meteor PK Django:谁更适合开发实时Web应用?
有人经常问Django是否支持单页面应用或事件驱动型架构。有人认为开发实时应用,前端可采用JavaScript MVC框架,其中Django可用于服务器端的开发。
-
Ruby On Rails实践现状调查结果
在这篇文章里,我们将与读者一起看一下部分Ruby调查结果,使大家对Ruby编程技术的现状有一个良好的认识。
-
开源市场仍存在大量就业机会
从脚本编程语言到开源服务器操作系统,再到移到应用开发人员,开源仍持续在为求职者提供着就业机会。