论坛首页 编程语言技术论坛

lightTPD + FASTCGI + Rails on Leopard 折腾记

浏览 11580 次
该帖已经被评为精华帖
作者 正文
   发表时间:2009-04-13  
拜读老大的性能分析贴 决定在mac上尝试一下 lightTPD + FASTCHI 这种 rails 部署方式

关于如何在 Leopard 上面编译安装, 这里有两篇极为详细的教程:
http://hivelogic.com/articles/view/ruby-rails-leopard
http://hivelogic.com/articles/view/installing-mysql-on-mac-os-x

同样也是从这个博主的文章中弄懂了 Unix-like 系统的目录结构, 明白了为什么要把自己编译的软件安装在 /usr/local/ 下面. (03年就把自己闷在宿舍装 RedHat, 可是后来一直对 Unix-like 类系统知之甚少.)
http://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard

有了前辈的探索, 这一路装来倒也没碰上太大的麻烦, 不过还是要注意以下几点:

ruby1.9 和 ruby-fcgi 不合, 研究如何部署到生产环境的话, 还是不要贪玩的好.

编译 mysql 的时候记得加 max 参数, rails 好多操作都是靠事务支持的, 所以离不开 InnoDB.
--with-plugins=max-no-ndb



关于下面的安装过程:
curl -O 代表下载文件, 要是你不喜欢这种方式, 也可以用别的软件来下载.
sudo 的前提是你得有个密码, 否则在输入密码那里直接回车是不被接受的.



第一步: 配置 PATH

也就是编译 .profile
mate ~/.profile


根据具体情况加入如下内容:
冒号分隔, 想要先查找的路径放前面, 最后那个 $PATH 代表系统原有的路径, 我们把它放到最末尾.
现在我们还没有这么多软件, 只是提前准备着.
export PATH="/usr/local/ruby/bin:/usr/local/mysql/bin:/usr/local/lighttpd/bin:/usr/local/fcgi/bin:/usr/local/pcre/bin:/usr/local/bin:/usr/local/sbin:$PATH"


重新加载 bash 配置
. ~/.profile


OK~, 根据前文提到的博主的建议, 让我们给源码建立一个目录统一管理:
sudo mkdir -p /usr/local/src
sudo chgrp admin /usr/local/src
sudo chmod -R 775 /usr/local/src
cd /usr/local/src




第二步: 安装 Ruby

虽然已经内置 ruby1.8.6 了, 不过我只是想亲自试一下安装过程.
内存大补贴(MBARIpatch)地址有点乱, 自己下载吧. http://sites.google.com/site/brentsrubypatches

curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.tar.gz
tar xzvf ruby-1.8.7-p72
tar xzvf MBARIp72patches.tar.gz
MBARIp72patches/apply ruby-1.8.7-p72
cd ruby-1.8.7-p72
./configure --prefix=/usr/local/ruby --enable-shared --enable-pthread CFLAGS="-O2 -fno-stack-protector -D_XOPEN_SOURCE=1"
make
sudo make install
cd ..


检查一下安上了没有:
which ruby
ruby -v




第三步: 安装 RubyGems

在你的 Mac 上面会有很多预置的 gem, 而且还 cleanup 不掉, 要是实在觉得碍眼, 可以查看一下路径, 然后重命名屏蔽掉, 但是千万别删除内置的 ruby, 否则后果很严重 (例如: textmate 失明.)
gem environment


curl -O http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz
tar xzvf rubygems-1.3.1.tgz
cd rubygems-1.3.1
sudo ruby setup.rb
cd ..


gem 命令可以通过以下命令查看
gem help commands

命令参数是可以进行简化输入的, 只要不产生歧义. 例如:
gem environment --> gem e
gem search --> gem sea



第四步: 安装 Rails

网慢是么? 把 rails 连同依赖包都下载到本地安装吧. 查看一下 rails 都依赖哪些 gem
gem dependency rails -v 2.3.2 -r


写这些文字的时候我看到的结果是6个 (其中 rake 要求 >= 0.8.3, 不过实际安装时却管我要 0.8.4, 不晓得为什么)
Gem rails-2.3.2
  rake (>= 0.8.3, runtime)
  activesupport (= 2.3.2, runtime)
  activerecord (= 2.3.2, runtime)
  actionpack (= 2.3.2, runtime)
  actionmailer (= 2.3.2, runtime)
  activeresource (= 2.3.2, runtime)

到 http://rubyforge.org 把这些 .gem 文件都下载回来, 放在一起, 文件名不要改.
sudo cp /Downloads/*.gem .
gem install -l rails-2.3.2.gem


速度很快吧~ 要是不安装文档会更快.
gem install -l rails-2.3.2.gem --no-rdoc --no-ri




第五步: 安装 Mysql

网上流行的编译参数, 具体这些参数的含义, 我这个菜鸟目前还无法回答, 注意 --with-plugins=max-no-ndb
编译和安装的过程有点长 (加起来大约20分钟), CPU 有点热...
curl -O http://mysql.mirror.tw/Downloads/MySQL-5.1/mysql-5.1.33.tar.gz
tar xzvf mysql-5.1.33.tar.gz
cd mysql-5.1.33
CC=gcc
CFLAGS="-O3 -fno-omit-frame-pointer"
CXX=gcc 
CXXFLAGS="-O3 -fno-omit-frame-pointer -felide-constructors 
-fno-exceptions -fno-rtti" 
./configure --prefix=/usr/local/mysql 
--with-extra-charsets=complex --enable-thread-safe-client 
--enable-local-infile --enable-shared --with-plugins=max-no-ndb
make
sudo make install
cd ..


既然是 DIY, 你就得自己运行脚本填充最初的系统表.
cd /usr/local/mysql
sudo ./bin/mysql_install_db --user=mysql
sudo chown -R mysql ./var


mac os x 是靠 launchd 守护进程运行的, 配置文件用的是 PropertyList (XML 格式), 通过观察发现大约每10秒检查一次, 发现进程不在就启动.

现在我们让 launchd 去看着 mysql, 保证它 7*24 都在运行.
方法是新建 /Library/LaunchDaemons/com.mysql.mysqld.plist 写入如下内容.
(问:为什么是这个名字? 答:我看 apple 内置的文件都是这样命令的, 看起来像是 com.公司.产品.plist)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>KeepAlive</key>
	<true/>
	<key>Label</key>
	<string>com.mysql.mysqld</string>
	<key>Program</key>
	<string>/usr/local/mysql/bin/mysqld_safe</string>
	<key>RunAtLoad</key>
	<true/>
	<key>UserName</key>
	<string>mysql</string>
	<key>WorkingDirectory</key>
	<string>/usr/local/mysql</string>
</dict>
</plist>

加入到 launchd 列表
sudo launchctl load -w /Library/LaunchDaemons/com.mysql.mysqld.plist

查看列表
launchctl list

解除守护
sudo launchctl unload -w /Library/LaunchDaemons/com.mysql.mysqld.plist


有了自己编译的 mysql, 当然少不了那个 C 版本的 ruby 驱动.
curl -O http://rubyforge.org/fsr/download.php/51087/mysql-ruby-2.8.1.tar.gz
tar xzvf mysql-ruby-2.8.1.tar.gz
cd mysql-ruby-2.8.1
ruby extconf.rb --with-mysql-dir=/usr/local/mysql
make
sudo make instal
cd ..


mysql 的 make 文件比较完整, 你可以随时通过这份编译好的源码卸载掉它
sudo make uninstall




第六步: 安装 FASTCGI
curl -O http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz
tar xzvf fcgi-2.4.0.tar.gz
cd fcgi-2.4.0
./configure --prefix=/usr/local/fcgi
make
sudo make install
cd ..


curl -O http://rubyforge.org/fsr/download.php/11368/ruby-fcgi-0.8.7.tar.gz
tar xzvf ruby-fcgi-0.8.7.tar.gz
cd ruby-fcgi-0.8.7
sudo ruby install.rb config -- --with-fcgi-include=/usr/local/fcgi/include --with-fcgi-lib=/usr/local/fcgi/lib
ruby install.rb setup
sudo ruby install.rb install
cd ..




第七步: 安装 lightTPD

老大的文章里告诫我们要先装 PCRE, 晚辈不敢怀疑:
curl -O ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-7.8.tar.gz
tar xzvf pcre-7.8.tar.gz
cd pcre-7.8
CFLAGS='-O2 -Wall'
./configure --prefix=/usr/local/pcre
make
sudo make instal
cd ..


有了前辈经验作为铺垫, 安装倒也简单:
curl -O http://www.lighttpd.net/download/lighttpd-1.4.22.tar.gz
tar xzvf lighttpd-1.4.22.tar.gz
cd lighttpd-1.4.22
./configure --prefix=/usr/local/lighttpd --with-pcre=/usr/local/pcre
make
sudo make install
cd ..


把默认配置文件复制出来
cp ./doc/lighttpd.conf /etc/lighttpd.conf


至于怎么配置, 有点超出我的能力范围了, 我只能勉强让它跑起来. 我只改动了下面几处:

开几个模块 mod_   rewrite access fastcgi simple_vhost cgi compress accesslog
指定路径的时候不能用 ~/ 这样的路径
指定日志 accesslog.filename = "/var/log/lighttpd/access.log"

$HTTP["host"] =~ ".+" {
  server.document-root = "/Users/colder/Sites/rails/public"
server.error-handler-404 = "/dispatch.fcgi"
fastcgi.server = (".fcgi" =>
( "localhost" =>
( "min-procs" => 3,
  "max-procs" => 3,
"socket" => "/tmp/rails.socket",
"bin-path" => "/Users/colder/Sites/rails/public/dispatch.fcgi",
"bin-environment" => ("RAILS_ENV" => "development")
)
)
)
}

launchd 的配置过程和 mysql 相似, 但也有点特殊. 从这份文件中可以看出如果守护的程序是带参数的, 那么第一个参数必须是程序本身. 参数名与参数值之前还不能留空格.
新建 /Library/LaunchDaemons/com.lighttpd.lighttpd.plist 写入如下内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>KeepAlive</key>
	<true/>
	<key>Label</key>
	<!-- 这就是个名字, 会显示在 launchctl list 里看到. -->
	<string>lighttpd</string>
	<key>OnDemand</key>
	<false/>
	<key>Program</key>
	<string>/usr/local/lighttpd/sbin/lighttpd</string>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/local/lighttpd/sbin/lighttpd</string>
		<!-- 这行很奇怪是吧? -f 后面紧挨着参数值, 你要不这样写, 就甭想启动. -->
		<string>-f/etc/lighttpd.conf</string>
		<string>-D</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
</dict>
</plist>

然后加载这个文件:
sudo launchctl load -w /Library/LaunchDaemons/com.lighttpd.lighttpd.plist


有了 launchd, mysql 和 lighttpd 的运行基本上不用担心了, 那 rails 的运行靠谁呢? 答案是 lighttpd. 配置文件说明了这一点, 当 lighttpd 启动的时候, 它会启动若干个 rails 实例 (数量由 min-procs 和 max-procs 决定). 即使是中途手动杀掉了 ruby 进程, 只要有请求进来, lighttpd 还是会去启动 rails 实例进行响应的.



OK~ 如果人品没有什么大问题的话, 到这里应该已经跑起来了, 这也正应了 rails 官方的那句台词:"先跑起来再说!"

如果跑不起来呢? 嗯! 我就碰到了下面的这个问题: 在 Windows 创建的 rails 项目, 复制到 Mac 上面就跑不起来了. 碰到这种情况, 看看你的rails目录下面的 public/dispatch.fcgi 开头第一句, 如果类似于: #!C:/Ruby/bin 这样的话, 请竖起中指!
然后心平气和的改成
#!/usr/local/ruby/bin/ruby

还有, 不要可惜了你的 Mac, 她不只有个光鲜的外表, 里边也很有内涵, 例如 tail
想知道 lighttpd 为什么启动不了的时候可以用它查看错误日志, 然后再一边修改配置, 一边回来查看这10秒一次的新日志.
tail -f /var/log/lighttpd/error.log

当然, 用在 rails 开发的时候会更合适:
tail -f ~/Sites/rails/log/development.log




经过这一番折腾, Rails 开发环境总算是跑起来了.
不是部署环境么?
呃. 就我目前的水平, 还不敢谈部署, 只想着用老大推荐的部署环境来开发, 就已经满意了, 至于什么时候谈部署, 还得慢慢来, 现在水平还太烂, 深入学习 *nix 和 rails 才一个月, 不敢奢望太多.

至少目前很多问题还不好解决, 例如:
不知道为什么后端有时候会死掉, 而且 lighttpd 又不会去重开. (手动杀的就可以重开).
偶尔还会出现连接失败(开发环境, 小量请求).
   发表时间:2009-04-15  
这篇文章写很好,投个精华。

其实在开发环境里面严格按照生产环境进行部署有很多好处:

1、确保你不会在代码发布到生产环境的时候,出现不可预知的问题。如果开发环境和生产环境存在差异,你很难确保代码上线以后不会遇到什么你无法想象的问题,特别是你的生产环境对稳定性要求很高的话。

2、对于类似JavaEye这样的多域名实现的rails项目,对域名,对端口都有一定的要求,即使在本地开发环境,也必须按照生产环境去配置,否则很多问题在开发环境无法被暴露出来。

3、像JavaEye这样的网站代码在本地运行的时候,你不可能把几十GB的附件,图片和头像都在自己的开发环境当中复制一份,所以你tail log,无论什么请求,后面都带有长长的404错误抛出,告诉你mongrel无法寻找到这些图片资源,其结果就是你的development.log根本无法有效查看。但是用lighty部署,可以避免掉这个问题,办法也很简单,以下十我在自己的MacBook开发环境的配置,用URL配置过滤掉静态资源往fcgi转发的可能性:

$HTTP["host"] =~ "^([a-zA-Z0-9\-\.]+).java.com$" {
  server.document-root = "/Users/robbin/projects/javaeye3/public"
  server.errorfile-prefix = "/Users/robbin/projects/javaeye3/public/error-"
  $HTTP["url"] !~ "(\.(js|css|gif|jpg|jpeg|bmp|png|ico|txt|swf|mp3|html|xml|htm|)$)|/javascripts/|/stylesheets/|/images/|/upload/" {
    server.error-handler-404 = "/dispatch.fcgi"
    fastcgi.server = (".fcgi" =>
      (
        ( "allow-x-send-file" => "enable",  "socket"=>"/Users/robbin/projects/lighttpd/javaeye.socket-0")
      )
    )
  }
}


4、最后,用mongrel的话,有些功能是无法实现的,比方说X-sendfile。

0 请登录后投票
   发表时间:2009-04-15  
to cncolder,你的文章写的很好,我也从中学到了不少知识。仅仅给你补充一点内容。

1、fcgi进程可以单独用spawn-fcgi命令来启动,不要用lighty去启动它。

从lighty1.4.22版本开始,spawn-fcgi被剥离到另外一个独立的项目去了,你要单独下载安装它,然后写个简单的shell
脚本来控制fcgi进程的启动和关闭,详细的配置方法在这里:独立启动fcgi进程和lighty通讯

2、lighty在OSX上面确实有点不稳定,偶然出现crash的现象,可以试试看添加这个参数:server.event-handler = "freebsd-kqueue"
0 请登录后投票
   发表时间:2009-04-15  
楼上几位消消气

我上次也问过robbin相关的问题,但是老大貌似没有时间去整这个环境。

现在看到lz的这个文章感觉上是很棒的,开发环境和生产环境一致的观点也很好。

另外,我直接删掉系统的ruby了,textmate失明,有没有办法解决?不想重灌系统。
0 请登录后投票
   发表时间:2009-04-15  
t0uch 写道
楼上几位消消气

我上次也问过robbin相关的问题,但是老大貌似没有时间去整这个环境。

现在看到lz的这个文章感觉上是很棒的,开发环境和生产环境一致的观点也很好。

另外,我直接删掉系统的ruby了,textmate失明,有没有办法解决?不想重灌系统。


我给你出个主意: 找你用Mac的同事,让他把系统自带的ruby相关的目录tar打包一下,然后拷贝给你,你在自己的Mac上面解压到同样的目录下面,就搞定了。
0 请登录后投票
   发表时间:2009-04-17   最后修改:2009-04-17
文章写的很仓促 可能条理性不是很好
原因是我熟悉mac和学ror的过程都太仓促 (春节过后换用mac, 3月开始接触rails, ruby也是双管齐下同时推进)
但是上面所用到的命令都是自己在摸索安装的过程中留下的笔记, 每一步都亲身尝试过.

robbin的建议要仔细看看 事实上对我来说 这些建议还一时难以消化 ~_~
  spawn-fcgi要从lighy中剥离, 不过1.4.22还没有剥离, 我的lighttpd进程倒是很健壮, 每天开机都能见到它, 中途也不休息, 我的困惑是后面的ruby进程经常消失.
  如果是我手动kill了ruby进程, lighttpd一接到请求就会帮我启动后端(从CPU使用率上就能明显看出来), 但是那种无端消失的情况, lighttpd就置之不理, 最后我只能连lighttpd进程一起kill掉, 然后几秒后这一家子就都重新回来了
  怪哉~
  专栏里的脚本是手动启动10个后端吧, 同样是socket连接, 不太清楚这种方法和前面的基本配置例子有什么区别.
  是lighttpd管理后端的能力不够强吗?

不只是开发环境比较生疏 对rails有时候也有太多的疑问
  infoQ在介绍resource_controller插件时讲到"丰满的模型, 精瘦的控制器"
  我不太喜欢插件, 就按照这个思路写了个helper来mix-in
  嗯~ 控制器真的精瘦了 类里面只剩一行代码
  这样做真的对吗? 我不知道.

t0uch "楼上几位消消气"
^^^ 我错过了什么吗? 没看懂这句.

要是早发现rails 就不至于在项目筹备阶段浪费这么久的时间了...
0 请登录后投票
   发表时间:2009-04-17  
t0uch 写道
楼上几位消消气

我上次也问过robbin相关的问题,但是老大貌似没有时间去整这个环境。

现在看到lz的这个文章感觉上是很棒的,开发环境和生产环境一致的观点也很好。

另外,我直接删掉系统的ruby了,textmate失明,有没有办法解决?不想重灌系统。



我也是如此,折腾了很久。
甚至吧textmate的boundles的ruby路径全改了一次。
我的解决方法是把你安装后的ruby 复制一份到删除的目录就可以了。
0 请登录后投票
   发表时间:2009-04-17  
现在终于知道  mysql  -MAx 是什么意思了。
谢谢LZ

关于
# ./configure --prefix=/usr/local/ruby --enable-shared --enable-pthread CFLAGS="-O2 -fno-stack-protector -D_XOPEN_SOURCE=1" 

我在这里遇到奇怪的问题,按照这种模式配置,生成的ruby速度巨慢。
测试脚本可以参见我之前写的:
http://blogs.iteye.com/blog/309223

运行下面这个程序,在我的环境里,最初的动运时间是15s左右,重新编译后是10s左右,如果发现有动行ruby比较慢的,可以重编译一下ruby

以上是1.8.7-p2版本。1.9的ruby版本,只要3S多。

新的编译参数

./configure

就是不加其它任何参数。
0 请登录后投票
   发表时间:2009-04-17  

Summary is below.
1. On MacOS X(10.5.5), Ruby1.8.7(p72) compiled with --enable-pthread
excute slowly,
   as Ruby use time of 70% at rb_call()->getcontext() in fib.rb

2. In MacPorts, ./configure with --enable-pthread option makes config.h
using getcontext
like below
#define HAVE_GETCONTEXT 1
#define HAVE_SETCONTEXT 1

3. If you comment out these two lines, you will get normal speed
Ruby1.8.7.

4. As Ruby1.9 don't use getcontext()/setcontext(), Ruby1.9 don't care
--enable-pthread.
1 请登录后投票
   发表时间:2009-04-17  
xhanxhanxhan 写道
现在终于知道  mysql  -MAx 是什么意思了。
关于
# ./configure --prefix=/usr/local/ruby --enable-shared --enable-pthread CFLAGS="-O2 -fno-stack-protector -D_XOPEN_SOURCE=1" 

我在这里遇到奇怪的问题,按照这种模式配置,生成的ruby速度巨慢。


ruby1.9能跑fastcgi吗? 我没搞定.

事实上 我只是让 rails 跑起来. 这个参数查看帮助时有说明:
./configure -h
...
  --enable-pthread   use pthread library.
...

看起来好像是个并发线程库? 如果说rails不支持多线程, 那这个参数似乎真的没什么用处了.
我是个新手, 目前实在是搞不清楚如何优化这些编译参数. 所以上面给出的参数只是保证编译不出错罢了.

不知道robbin老大什么时候会有时间给我们解释一下这几个服务器软件的编译参数和优化心得.
1 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics