搭建Rails 3.1+lighttpd+FastCGI环境

标签:Ruby

上周和几个Ruby程序员打起了嘴仗,勾起了我对Rails的一点兴趣,于是就想搭建一个Rails玩玩吧。结果过程非常艰辛,遂记录下来以避免以后重蹈覆辙。

先说明一下,环境和之前测试时一样:
宿主:MacBook Pro MC700
操作系统:Mac OS X 10.6.8
CPU: 2.3GHz Intel Core i5(双核)
内存:4 GB

虚拟机:Virtual Box
操作系统:Linux version 2.6.32-5-686 (Debian 2.6.32-35)
CPU: 限制到40%宿主CPU,单核(2.3 * 40% = 0.92GHz)
内存:512 MB
唯一不同的是加大了虚拟机内存,因为Ruby消耗的资源较多,而且安装过程中需要编译,内存太小会占用很多swap。

于是开始安装Ruby,这玩意不像Perl和Python是自带的,所以需要自己安装。
目前的最新的稳定版是Ruby 1.9.2-p290,把源码下载下来,直接解压编译就行了。
不过看安裝Rails開發環境,貌似先安装这些东西比较好:
apt-get install build-essential zlib1g-dev libssl-dev libreadline5-dev
装好后运行ruby -v,可以看到:ruby 1.9.2p290 (2011-07-09 revision 32553) [i686-linux]。或者运行irb,可以进入Ruby命令行模式,这就表示安装成功了。

接着安装Rails,直接用gem就能安装了:
gem install rails
坑爹的是下载时没有任何提示,还能继续打字,我还以为是输错了命令…
最后放在一边吃饭去了,过了十多分钟后发现在安装了…
装完后运行rails -v,看到Rails 3.1.0就表示装好了。

然后按照Rails起步走的描述建一个demo项目:
rails new demo

接着运行bundle install,等待很久以后会发现提示缺少一些东西,而且它还不能自动帮我安装。
这些东西一般都是在Gemfile里定义的,可以对照一下缺了什么。
再运行gem install 缺少的东东。
如果找不到,再运行apt-get install 缺少的东东。
还不行的话就搜索一下,找到源码自己编译吧…
这个过程重复了数次后,终于全部装完了。
运行rails s,发现成功启动了。

于是按第一個Hello World!!描述的生成一个controller,并在config/routes.rb里设置路径。
至于那个controller,因为我并不想用模版,于是需要稍作修改:
class WelcomeController < ApplicationController
	def say
		render :text => "hello"
	end
end

因为修改了routes.rb,所以需要重启一下WEBrick服务器。
接着在浏览器里输入地址访问,大概过了4、5秒后,这个hello world终于出现了…
不过后续的访问就很快了,看log大概每个view只花了0.2 ms。
于是ab测试了一下,大概42 QPS的样子,慢得离谱…

此外,rails c可以进入命令行模式,不过我运行时提示缺少readline,最后是这样处理的:
apt-get install libncurses5-dev libreadline5-dev
cd ~/ruby-1.9.2-p290/ext/readline/
ruby extconf.rb
make && make install

之后想起可以设置production环境,于是尝试了各种办法,最后发现编辑config/boot.rb,加上这行代码即可:
ENV["RAILS_ENV"] = 'production'
速度提高到49 QPS,仍然很囧。

查了一下资料,说WEBrick是Ruby写的,性能很差,只适合开发用。
于是去找了下别的部署方式。根据robbin的RoR部署方案深度剖析,lighttpd+FastCGI应该是性能最好的方式,浅析Ruby on Rails部署方案这篇测试也印证了这个观点。
虽然这2篇文章都比较老了,Rails官网上的推荐方式中也没有FastCGI,不过我想其他方式毕竟需要解析文本方式的HTTP,不可能快过二进制的FastCGI,于是就用它吧。

先装lighttpd,直接apt-get的版本是1.4.28,官网最新版本是1.4.29,不过新增功能我用不到,也没性能上的改进,于是将就吧。
装上以后按照在Ubuntu下安装和配置Rails 3详解 (LightTPD + FastCGI)这篇文章修改一下/etc/lighttpd/lighttpd.conf的设置。
我的大致如下:
server.modules = (
	"mod_accesslog",
	"mod_access",
	"mod_alias",
	"mod_compress",
	"mod_redirect",
	"mod_rewrite",
	"mod_fastcgi",
)

server.error-handler-404 = "/dispatch.fcgi"

fastcgi.server = (".fcgi" => ((
	"socket"=>"/tmp/rails.socket",
	"max-procs" => 1,
	"bin-path" => "/home/keakon/www/demo/public/dispatch.fcgi",
	"bin-environment" => ("RAILS_ENV" => "production")
)))
       
server.document-root        = "/home/keakon/www/demo/public"
# 其余基本保留默认配置

要注意的是public/dispatch.fcgi在Rails 3.1里并没有自带,所以需要自己创建一个:
#!/usr/local/bin/ruby
	
require_relative '../config/environment'
	
class Rack::PathInfoRewriter
	def initialize(app)
		@app = app
	end
	
	def call(env)
		env.delete('SCRIPT_NAME')
		parts = env['REQUEST_URI'].split('?')
		env['PATH_INFO'] = parts[0]
		env['QUERY_STRING'] = parts[1].to_s
		@app.call(env)
	end
end
	
Rack::Handler::FastCGI.run Rack::PathInfoRewriter.new(Demo::Application)
注意最后那行的Demo改成项目名。

接着安装FastCGI和FastCGI for Ruby,详解中有说明。其实我在看此文之前,就在这一步卡壳了…

再运行service lighttpd restart重启一下lighttpd,应该就能访问了,不过第一次访问差不多要10秒…
于是ab测试了一下,速度上升到200 QPS了,泪流满面。但是并发数超过100时就很容易出错,看来稳定性还不够。
内存消耗也很大,128 MB的小VPS就不用考虑了。如果还要运行MySQL的话,256 MB以上才够用。据robbin说,JavaEye在2008年时,每个Ruby进程消耗180 MB内存,现在估计也不会少(因为功能增加了很多)。

值得一提的是,虽然看上去都很好,不过首页还是静态文件,于是再次修改config/routes.rb,加上这行代码:
root :to => 'welcome#say'
访问一下发现还是没变化,于是把public/index.html删除,结果变成lighttpd显示的文件目录了…

想了下原因,应该是lighttpd.conf造成的。实际上按照正常的做法,应该用URL重写的方法,但这里采用的是404,因为robbin说这样更快。遗憾的是首页是不会404的,这估计是lighttpd的默认实现吧…
解决办法可以按照Lighttpd的配置来改成URL重写,不过我的处理方式是在index-file.names里加上"dispatch.fcgi",试了下也管用,性能和404方式持平。

其实还想测试一下ActiveRecord的性能,不过研究半天后还是放弃了。
首先是安装时被mysql2这个gem折腾;接着发现我只会依葫芦画瓢地创建数据库,但是不会使用已经存在的数据库。
不过以我的经验,这种ORM应该会稍微影响数据库性能。最让我担忧的是ActiveRecord的动态方法,如果实现方式和Python差不多的话,这种访问属性的效率应该是非常低的。

最后拿Tornado测了下hello world,在1000并发下也没问题,轻松跑到500 QPS。
话说昨天上午还看到一篇RAILS 3 PERFORMANCE - NOT GOOD ENOUGH,让我惊讶的是Ruby的时间占用居然超过了数据库…
The Computer Language Benchmarks Game测试,Ruby 1.9.2的速度应该不错,至少比PHP、Python 3和Perl都快。
不过以前在GAE上测试webapp和Django时,单个hello world的请求分别要消耗4ms和10ms。可见在这种无数据库访问的情况下,或是数据库时间和脚本运行时间在一个数量级时,框架本身还是很影响性能的。只不过以20ms为例,当QPS达到50时,每天的请求都已经达到400万了,我想也有足够的钱买更多更好的服务器了。

3条评论 你不来一发么↓ 顺序排列 倒序排列

    向下滚动可载入更多评论,或者点这里禁止自动加载

    想说点什么呢?