在使用capistrano"零停机"部署后,Unicorn工作人员超时

Del*_*ero 6 deployment capistrano ruby-on-rails unicorn ruby-on-rails-3

我正在运行Rails 3.2.21应用程序并使用capistrano(nginx和unicorn)部署到Ubuntu 12.04.5框.

我的应用程序设置为零停机部署(至少我认为),我的配置文件看起来或多或少像这些.

问题在于:当部署几乎完成并重新启动独角兽时,当我看到我的unicorn.log时,我看到它启动了新工作人员,收获了旧工作人员......但是我的应用程序只挂了2-3分钟.此时对应用程序的任何请求都会达到超时窗口(我设置为40秒)并返回应用程序的500错误页面.

这是unicorn.log输出的第一部分,因为独角兽正在重启(我有5个独角兽工人):

I, [2015-04-21T23:06:57.022492 #14347]  INFO -- : master process ready
I, [2015-04-21T23:06:57.844273 #15378]  INFO -- : worker=0 ready
I, [2015-04-21T23:06:57.944080 #15381]  INFO -- : worker=1 ready
I, [2015-04-21T23:06:58.089655 #15390]  INFO -- : worker=2 ready
I, [2015-04-21T23:06:58.230554 #14541]  INFO -- : reaped #<Process::Status: pid 15551 exit 0> worker=4
I, [2015-04-21T23:06:58.231455 #14541]  INFO -- : reaped #<Process::Status: pid 3644 exit 0> worker=0
I, [2015-04-21T23:06:58.249110 #15393]  INFO -- : worker=3 ready
I, [2015-04-21T23:06:58.650007 #15396]  INFO -- : worker=4 ready
I, [2015-04-21T23:07:01.246981 #14541]  INFO -- : reaped #<Process::Status: pid 32645 exit 0> worker=1
I, [2015-04-21T23:07:01.561786 #14541]  INFO -- : reaped #<Process::Status: pid 15534 exit 0> worker=2
I, [2015-04-21T23:07:06.657913 #14541]  INFO -- : reaped #<Process::Status: pid 16821 exit 0> worker=3
I, [2015-04-21T23:07:06.658325 #14541]  INFO -- : master complete
Run Code Online (Sandbox Code Playgroud)

之后,随着应用程序挂起2-3分钟,这是正在发生的事情:

E, [2015-04-21T23:07:38.069635 #14347] ERROR -- : worker=0 PID:15378 timeout (41s > 40s), killing
E, [2015-04-21T23:07:38.243005 #14347] ERROR -- : reaped #<Process::Status: pid 15378 SIGKILL (signal 9)> worker=0
E, [2015-04-21T23:07:39.647717 #14347] ERROR -- : worker=3 PID:15393 timeout (41s > 40s), killing
E, [2015-04-21T23:07:39.890543 #14347] ERROR -- : reaped #<Process::Status: pid 15393 SIGKILL (signal 9)> worker=3
I, [2015-04-21T23:07:40.727755 #16002]  INFO -- : worker=0 ready
I, [2015-04-21T23:07:43.212395 #16022]  INFO -- : worker=3 ready
E, [2015-04-21T23:08:24.511967 #14347] ERROR -- : worker=3 PID:16022 timeout (41s > 40s), killing
E, [2015-04-21T23:08:24.718512 #14347] ERROR -- : reaped #<Process::Status: pid 16022 SIGKILL (signal 9)> worker=3
I, [2015-04-21T23:08:28.010429 #16234]  INFO -- : worker=3 ready
Run Code Online (Sandbox Code Playgroud)

最终,在2或3分钟后,应用程序再次开始响应,但一切都更加缓慢.您可以在New Relic中清楚地看到这一点(水平线标记部署,浅蓝色区域表示Ruby):

部署期间和之后的新Relic图

我有一个相同的登台服务器,我无法在登台中复制问题...已授予,登台是空载(我是唯一一个尝试发出页面请求的人).

这是我的config/unicorn.rb文件:

root = "/home/deployer/apps/myawesomeapp/current"
working_directory root

pid "#{root}/tmp/pids/unicorn.pid"
stderr_path "#{root}/log/unicorn.log"
stdout_path "#{root}/log/unicorn.log"

shared_path = "/home/deployer/apps/myawesomeapp/shared"

listen "/tmp/unicorn.myawesomeapp.sock"
worker_processes 5
timeout 40

preload_app true

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

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

  old_pid = "#{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

    end
  end
end

after_fork do |server, worker|
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
  end
end
Run Code Online (Sandbox Code Playgroud)

只是为了描绘一幅完整的图片,在我的capistrano deploy.rb中,unicorn restart任务看起来像这样:

namespace :deploy do
  task :restart, roles: :app, except: { no_release: true } do
    run "kill -s USR2 `cat #{release_path}/tmp/pids/unicorn.pid`"
  end
end
Run Code Online (Sandbox Code Playgroud)

任何想法为什么独角兽工人在部署后立即超时?我认为零停机时间的关键是要保持旧的停机时间,直到新的旋转并准备服务?

谢谢!

UPDATE

我做了另一次部署,这一次关注production.log,看看那里发生了什么.唯一可疑的是以下几行,这些行与正常请求混在一起:

Dalli/SASL authenticating as 7510de
Dalli/SASL: 7510de
Dalli/SASL authenticating as 7510de
Dalli/SASL: 7510de
Dalli/SASL authenticating as 7510de
Dalli/SASL: 7510de
Run Code Online (Sandbox Code Playgroud)

更新#2

正如下面的一些答案所示,我更改了before_fork块以添加,sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU因此工作人员将逐渐被杀死.

同样的结果,非常慢的部署,具有相同的尖峰,如上图所示.仅仅为了上下文,在我的5个工作进程中,前4个发送了一个TTOU信号,第5个发送了QUIT.不过,似乎没有什么区别.

tra*_*ong 3

我最近在尝试在 Digital Ocean 上设置 Rails/Nginx/Unicorn 时遇到了类似的问题。经过一些调整后,我能够实现零停机部署。这里有一些可以尝试的事情:

  1. 减少工作进程的数量。
  2. 增加服务器的内存。我在 512MB RAM Droplet 上遇到超时。当我将其增加到 1GB 时,似乎解决了这个问题。
  3. 使用“capistrano3-unicorn”宝石。
  4. 如果 preload_app true,则使用重新启动 (USR2)。如果为 false,则使用重新加载 (HUP)。
  5. 确保“tmp/pids”在deploy.rb中作为linked_dirs集中。
  6. 用于px aux | grep unicorn确保旧进程被删除。
  7. 用于kill [pid]手动停止任何仍在运行的 unicorn 进程。

这是我的独角兽配置供参考:

working_directory '/var/www/yourapp/current'
pid '/var/www/yourapp/current/tmp/pids/unicorn.pid'
stderr_path '/var/www/yourapp/log/unicorn.log'
stdout_path '/var/www/yourapp/log/unicorn.log'
listen '/tmp/unicorn.yourapp.sock'
worker_processes 2
timeout 30
preload_app true

before_fork do |server, worker|
  old_pid = "/var/www/yourapp/current/tmp/pids/unicorn.pid.oldbin"
  if old_pid != server.pid
    begin
    sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
    Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

部署.rb

lock '3.4.0'

set :application, 'yourapp'
set :repo_url, 'git@bitbucket.org:username/yourapp.git'
set :deploy_to, '/var/www/yourapp'
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml', 'config/application.yml')
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
set :format, :pretty
set :log_level, :info
set :rbenv_ruby, '2.1.3'

namespace :deploy do
  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
    end
  end
end

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    #invoke 'unicorn:reload'
    invoke 'unicorn:restart'
  end
end
Run Code Online (Sandbox Code Playgroud)