世界上最伟大的投资就是投资自己的教育

首页服务器部署
随风 · 练气

部署之使用 mina 来部署 Ruby on Rails 应用之 unicorn (八)

随风发布于2379 次阅读

1. 介绍

unicorn是一个运行 ruby 应用的 HTTP 服务器。当你写完了 ruby 应用,准备部署时,就可以用它来运行 ruby 应用。但一般来说,我们不会直接那样用,我们会结合 nginx 来用,把高性能的 nginx 暴露在最外层,而反向代理到 unicorn。nginx 是一个静态 web 服务器,它是部署在 80 端口,一般来说,它会处理所有的静态文件请求,比如 css,js 等,假如需要动态的内容,它就会转发给 unicorn,而 unicorn 做一些处理,比如查数据库等,处理完,再转交给 nginx,最后 nginx 发送给用户,所以整个过程都是 nginx 在起一个缓冲和保护的作用,用户并没有感觉到 unicorn 的存在。

这种处理方式跟 apache 有很大的不同,比如说处理 php 的 mod_php 模块。apache 也是跟 nginx 一样,是个静态服务器。它本身不能解析 php 解析,要解析 php 脚本,就必须得装 php 解析的组件,可以把这组件编译进 apache 中,也可以以动态加载的形式来加载。但无论怎样,这个模块本身就会在处理 php 请求时成为 apache 的一部分,处理的效率和性能就取决于这个模块本身。而 nginx 不一样,它处理 ruby 动态的请求和静态文件的请求是分开的,静态文件它自己能处理,而动态的,它通过反向代理来转发,这两部分本身就分开了,这样就很灵活了,因为 nginx 本身性能高,能起到保护的作用,而后面的 unicorn 进程也有自己的空间,可以尽量发挥自己的功能和作用。比如,unicorn 也有类似于 nginx 的 master-worker 的进程模式,这样可以部署多个 unicorn 形成负载均衡。unicorn 本身也是一个 gem,这样就不用像 mod_php 那样编译或安装 nginx 的组件,这样很灵活,假如以后要把 unicorn 换成 puma,也是很方便的事。

unicorn 还支持 copy-on-write-friendly(写时复制),高效利用内存。还支持监听到 unix socket 等功能。

unicorn 是多进程的处理请求的模式,而且它还是预先 folk(prefork)。也就是说,在启动服务的时候就会先创建好进程。一般来说,假如你有两个核心的 cput,那就会创建一个 master 进程,两个 worker 进程,请求进来了,由 master 来分配给 worker 处理,这点跟 nginx 的机制差不多。

2. 使用

我们会使用mina结合nginx来部署 unicorn 应用。

我们需要先把 unicorn 进程给跑起来,而它是以监听 unix socket 的方式跑的,而 nginx 也是把请求转发到 unicorn 的 unix socket,unix socket 是一种套接字,先把它想象成一个文件。

用 mina 来部署 unicorn 进程需要一个 gem,叫mina-unicorn

2.1 mina-unicorn

unicorn 本身也是一个 linux 的命令行程序,而 mina-unicorn 就是根据 unicorn 命令结合 linux 的 kill 命令来封装的。它的源码也是比较简单的。

在 Gemfile 文件中添加下面一行。

gem 'mina-unicorn', :require => false
gem 'unicorn'

执行 bundle 安装。

添加下面一行到config/deploy.rb文件中。

require 'mina/unicorn'

设置 socket 和 pid 文件放置的目录位置。

socket 是 unicorn 监听的文件套接字,而 pid 是一个进程标识符,是个整数,linux 一般用它配合 kill 指令来控制进程的启动,重启等,比如"kill cat /tmp/unicorn.pid"。

# socket文件和pid文件会放在下面的目录中,这个可以查看源码获知详情。
set :shared_paths, ['tmp/sockets', 'tmp/pids']

找到config/deploy.rbtask :setup => :environment的部分,添加下面两段。

task :setup => :environment do
  ...

  queue! %[mkdir -p "#{deploy_to}/#{shared_path}/tmp/sockets"]
  queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/tmp/sockets"]

  queue! %[mkdir -p "#{deploy_to}/#{shared_path}/tmp/pids"]
  queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/tmp/pids"]

  ...
end

然后运行下面的命令。

mina setup

这个作用是在部署目录下的 shared 目录下生成tmp/socketstmp/pids目录。

做完这些,还差一步,就是需要部署完应用的时候,重启 unicorn。

config/deploy.rb文件中找到task :deploy => :environment部分添加invoke :'unicorn:restart'这一行,如下所示。

desc "Deploys the current version to the server."
task :deploy => :environment do
  to :before_hook do

  end
  deploy do
   ...

    to :launch do
      invoke :'unicorn:restart'
      ...
    end
  end
end

在 config 目录下新增一个文件叫unicorn.rb,这个是 unicorn 的配置文件,内容如下:

app_path = File.expand_path( File.join(File.dirname(__FILE__), '..', '..'))
worker_processes   1
timeout            180
listen             "#{app_path}/shared/tmp/sockets/unicorn.sock"
pid                "#{app_path}/shared/tmp/pids/unicorn.pid"
stderr_path        "log/unicorn.log"
stdout_path        "log/unicorn.log"

before_fork do |server, worker|
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  end

  old_pid = "#{server.config[: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
end

after_fork do |server, worker|
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
  end
end

before_exec do |server|
  ENV["BUNDLE_GEMFILE"] = "#{app_path}/current/Gemfile"
end

其中worker_processes跟你主机的 cpu 核数保持一致就好了。其他的不用改。官方也提供了样板文件,我也是参考样板文件作修改的。

现在就可以部署了。

mina deploy

现在可以进入部署的主机,查看部署目录下的 shared 目录下的tmp/sockets目录是不是生成了 unicorn.sock 文件。

2.2 nginx

现在 unicorn 跑起来,还需要一个接口把 nginx 反向代理到 unicorn,这个通过配置 nginx 就好了。

/etc/nginx/conf.d下新增一个配置文件,比如叫 rails.conf。

upstream rails365 {
    # Path to Unicorn SOCK file, as defined previously
    server unix:///home/yinsigan/rails365/shared/tmp/sockets/unicorn.sock fail_timeout=0;
}
server {
    listen 80 default_server;
    server_name www.rails365.net;
    root         /home/yinsigan/rails365/current/public;
    keepalive_timeout 70;

    location ~ ^/assets/ {
       gzip_static on;
       expires max;
       add_header Cache-Control public;
    }

        try_files $uri/index.html $uri @rails365;
    location @rails365 {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://rails365;
    }

    # redirect server error pages to the static page /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }

}

server {
  listen 80;
  server_name rails365.net;

  return 301 $scheme://www.rails365.net$request_uri;
}

关键是反向代理的那部分,就是try_fileslocation @rails365还有upstream rails365这几个地方。

我部署到的目录是/home/yinsigan/rails365root,还有 socket 的位置都要指向正确的。

最后执行以下命令让配置生效。

sudo nginx -s reload

现在可以尝试访问你的网站看是否生效了。

另外,关于 nginx 的配置可以查看本站的相关文档

完结。

本站文章均为原创内容,如需转载请注明出处,谢谢。

0 条回复
暂无回复~~
喜欢
我的微信官网服务号精品文章订阅号微信视频号
程序员随风
统计信息
    学员: 22744
    视频数量: 1492
    文章数量: 466

© 汕尾市求知科技有限公司 | 专业版网站 | 关于我们 | 在线学员:1151

粤公网安备 44152102000088号粤公网安备 44152102000088号 | 粤ICP备19038915号

Top