蝉游记网站的部署

标签: 游记 网站 | 发表时间:2013-06-30 23:25 | 作者:
出处:http://simple-is-better.com/

蝉游记(  http://chanyouji.com )网站之前用Nginx+Passenger+自制script来部署,随着用户增多,移动app的api调用增加,服务器增多和无缝部署重启的需求,转移到了Nginx+Unicorn+Capistrano,写篇博客记录一下各种细节和需要注意的地方。 

1. Nginx的配置 
 

gzip  on;
#开启gzip,同时对于api请求的json格式也开启gzip
gzip_types application/json;

#每台机器都运行nginx+unicorn,本机用domain socket,方便切换
upstream ruby_backend {
    server unix:/tmp/unicorn.sock fail_timeout=0;
    server 10.4.8.34:4096 fail_timeout=0;
    server 10.4.3.8:4096 fail_timeout=0;
}

#用try_files方式和proxy执行rails动态请求
server {
    listen       80;
    server_name  chanyouji.com;
    root         /www/youji_deploy/current/public;

    try_files $uri/index.html $uri.html $uri @httpapp;

    location @httpapp {
      proxy_redirect     off;
      proxy_set_header   Host $host;
      proxy_set_header   X-Forwarded-Host $host;
      proxy_set_header   X-Forwarded-Server $host;
      proxy_set_header   X-Real-IP        $remote_addr;
      proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
      proxy_buffering    on;
      proxy_pass         http://ruby_backend;
   }
}

#用不同的域名提供静态资源服务,减少主域名带来的cookie请求和方便做cdn源
server {
    listen       80;
    server_name  cdn.chanyouji.cn cdnsource.chanyouji.cn;
    root         /www/youji_deploy/current/public;

    location ~ ^/(assets)/  {
      root /www/youji_deploy/current/public;
      gzip_static on; # to serve pre-gzipped version
      expires max;
      add_header Cache-Control public;
    }
}



2 unicorn.rb的配置 
 

worker_processes 6

app_root = File.expand_path("../..", __FILE__)
working_directory app_root

# Listen on fs socket for better performance
listen "/tmp/unicorn.sock", :backlog => 64
listen 4096, :tcp_nopush => false

# Nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 30

# App PID
pid "#{app_root}/tmp/pids/unicorn.pid"

# By default, the Unicorn logger will write to stderr.
# Additionally, some applications/frameworks log to stderr or stdout,
# so prevent them from going to /dev/null when daemonized here:
stderr_path "#{app_root}/log/unicorn.stderr.log"
stdout_path "#{app_root}/log/unicorn.stdout.log"

# To save some memory and improve performance
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
  GC.copy_on_write_friendly = true

# Force the bundler gemfile environment variable to
# reference the Сapistrano "current" symlink
before_exec do |_|
  ENV["BUNDLE_GEMFILE"] = File.join(app_root, 'Gemfile')
end

before_fork do |server, worker|
  # 参考 http://unicorn.bogomips.org/SIGNALS.html
  # 使用USR2信号,以及在进程完成后用QUIT信号来实现无缝重启
  old_pid = app_root + '/tmp/pids/unicorn.pid.oldbin'
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us
    end
  end

  # the following is highly recomended for Rails + "preload_app true"
  # as there's no need for the master process to hold a connection
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  # 禁止GC,配合后续的OOB,来减少请求的执行时间
  GC.disable
  # the following is *required* for Rails + "preload_app true",
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end



3. GC OOB 
这篇newrelic的文章解释很清楚: http://blog.newrelic.com/2013/05/28/unicorn-rawk-kick-gc-out-of-the-band/ 
就是将GC延迟到用户请求完成以后,这样就会缩短响应时间,配合现成的gem unicorn-worker-killer 也不用担心内存爆掉。 

在config.ru里面配置: 

require 'unicorn/oob_gc'
require 'unicorn/worker_killer'
#每10次请求,才执行一次GC
use Unicorn::OobGC, 10
#设定最大请求次数后自杀,避免禁止GC带来的内存泄漏(3072~4096之间随机,避免同时多个进程同时自杀,可以和下面的设定任选)
use Unicorn::WorkerKiller::MaxRequests, 3072, 4096
#设定达到最大内存后自杀,避免禁止GC带来的内存泄漏(192~256MB之间随机,避免同时多个进程同时自杀)
use Unicorn::WorkerKiller::Oom, (192*(1024**2)), (256*(1024**2))

require ::File.expand_path('../config/environment',  __FILE__)
run Youji::Application



4. Capistrano部署脚本 

set :unicorn_config, "#{current_path}/config/unicorn.rb"
set :unicorn_pid, "#{current_path}/tmp/pids/unicorn.pid"

namespace :deploy do
  task :start, :roles => :app, :except => { :no_release => true } do
    run "cd #{current_path} && RAILS_ENV=production bundle exec unicorn_rails -c #{unicorn_config} -D"
  end
 
  task :stop, :roles => :app, :except => { :no_release => true } do
    run "if [ -f #{unicorn_pid} ]; then kill -QUIT `cat #{unicorn_pid}`; fi"
  end
  
  task :restart, :roles => :app, :except => { :no_release => true } do
    # 用USR2信号来实现无缝部署重启
    run "if [ -f #{unicorn_pid} ]; then kill -s USR2 `cat #{unicorn_pid}`; fi"
  end
end


完成这些改进以后,部署蝉游记的新版本就只用输入cap production deploy,然后就可以喝茶去了,也不用担心用户在重启动的时候会有短期卡死的问题

# 来源: I am sailing, I am sailing


在微博上关注: 新浪, 腾讯   投稿

最新招聘

更多>>

相关 [游记 网站] 推荐:

蝉游记网站的部署

- - python.cn(jobs, news)
蝉游记(  http://chanyouji.com )网站之前用Nginx+Passenger+自制script来部署,随着用户增多,移动app的api调用增加,服务器增多和无缝部署重启的需求,转移到了Nginx+Unicorn+Capistrano,写篇博客记录一下各种细节和需要注意的地方. gzip on; #开启gzip,同时对于api请求的json格式也开启gzip gzip_types application/json; #每台机器都运行nginx+unicorn,本机用domain socket,方便切换 upstream ruby_backend {.

泰国归来游记

- emilo - 创意悠悠花园
一直想着休假的时候去那里旅游合适,刚开始选定的是国内的云南之类的,后来一看价格,觉得3000多还不如出国呢,于是就选定了途牛网的泰国游<曼谷-芭提雅6或7日>沙美岛海滩PUB,米其林绿光森林餐厅 这条线路. 其它的废话就不多说了,说一下这次旅游过程中的一些感受吧. 泰国是一个佛教国家,全国大约有3W多寺庙,而且旅游的过程中会有进入寺庙的情况,所以,如果有不同信仰的朋友,注意不要做出什么不敬的行为.

令人蛋疼的《西游记》

- Liming - 天朝娱乐 | 每天开心一下!
猜您喜欢: 解决有史以来80后对西游记的困惑. 这个西游记实在太搞了,强大的配音啊. 西游记天朝热门广告串烧 无觅.

《西游记》之唐僧身世之谜

- Septem - 无聊哦
西游记讲的是唐僧取经,要讲唐僧,我们得先从唐僧的父母亲讲起. 在西游记的《陈光蕊赴任逢灾 江流僧复仇报本》这一回中, 疑点多多, 迷雾重重, 很难于读懂. 然此篇正是作者立意高远之处, 读懂了, 方能明白何为“造化”,读不懂, 《西游记》就永远只能是儿童故事. 唐僧的父亲叫陈光蕊,唐僧的母亲叫殷温娇.

2011北欧游记(9)吃的

- Xinyu - 撒把盐
在北欧五个多星期,什么都好,最难熬的是吃的,每天面对黄油奶酪面包饼干酸奶,郁闷死了. 一般对中国人而言,尤其是那些挑嘴的,连续两周吃西餐已经是挑战了,三周就到极限. 好些朋友都说出去最多三周就要回来. 记得第一次去瑞典,连续吃了一周的硬面包之后,早晨起来咬肌酸疼得不行. 中国人出去还有个习惯,带一瓶老干妈,和一些咸菜,如果出去时间长一点,会带些豆瓣酱之类的调料好自己做菜.

香港迪士尼公园游记

- - 陈轶的盛夏厅
很小的时候就听说过迪士尼,还挺过迪士尼帮助绝症儿童实现他到迪士尼一游的梦想的心愿,一直梦想着去迪士尼乐园,直到我长大了,意识到这世界很多事情想像远比现实美好. 后来迪士尼在我眼中的形象:老朽,跟不上潮流,本行动画片被皮克斯彻底击败,最后巨资收购皮克斯,自从它收购皮克斯以后,皮克斯的影片质量每况愈下,我觉得肯定是因为迪士尼在后面添乱.

网站推荐:IFTTT(if this then that)

- 小皮球香蕉梨 - 有意思吧
这是一个神奇的网站,比某电视上天天放的那个广告要神奇许多. 就像它的域名 ifttt.com 一样,虽然丑却十分个性. 昨天晚上,ifttt.com 在 Twitter 被瞬间引爆,每个被邀请的人都会再拥有5个邀请名额,源源不断的邀请让 Geek 很兴奋. 那么,ifttt 到底是什么呢. 这是一个条件触发网站,当 A 条件触发时,自动激发 B 条件发生.

Facebook 网站架构

- - idea's blog
我收集到一些文章和视频, 可以带你窥探 Facebook 的架构. Facebook 承载了几十亿的用户, 它的架构(包括思想和实现)是非常值得参考的. 当然, 你要小心不要照搬 Facebook 的每一字一句, 因为任何思想和实现都是有自己的应用场景的.. Google Talk 界面开发分析. 使用Python POST任意的HTTP数据以及使用Cookie.

过去的《西游记》到底有多狗血 你可能不知道的《西游记》

- Alucard - 囧片王
原来经典的83版《西游记》也有很多穿帮镜头;. 原来日本在中国之前就拍了《西游记》而且堪称史上最囧《西游记》;. 老湿第6部:令人蛋疼的《西游记》:.

用BrowserID注册网站

- ashuai - Solidot
Mozilla宣布了一个实验项目BrowserID,提供了一种注册网站的新方法. 注册网站通常的方法是电子邮件验证,造成用户时间的浪费,要求用户登录另一个网站,记住另一个密码. BrowserID(源代码发布在github上)提供了一种更简单的方法,消除了电子邮件验证. 它是Verified Email Protocol实现,基于公钥系统和Mozilla的认证服务器,以确保用户身份的真实性.