【问题标题】:Am I preloading the app in Heroku + Unicorn correctly?我是否正确地在 Heroku + Unicorn 中预加载了应用程序?
【发布时间】:2012-02-18 22:31:27
【问题描述】:

在 Heroku 上使用 Unicorn 时。扩大规模会有问题,因为新扩大的网络测功机可以在仍在加载应用程序时通过请求访问。这主要导致超时错误。

我在http://codelevy.com/2010/02/09/getting-started-with-unicorn.htmlhttps://github.com/blog/517-unicorn 做了一些阅读

这两篇文章建议使用preload_app true。还有一个after_forkbefore_fork 块。

在 Rails 3+ 中,before_block 中的代码仍然需要吗?我在某处读过,否则。有谁有过设置的经验并愿意分享吗?

我还有什么遗漏吗?我是否正确预加载了应用程序?

# config/initializers/unicorn.rb
# Read from:
# http://michaelvanrooijen.com/articles/2011/06/01-more-concurrency-on-a-single-heroku-dyno-with-the-new-celadon-cedar-stack/
worker_processes 3 # amount of unicorn workers to spin up
timeout 30         # restarts workers that hang for 90 seconds

# Noted from http://codelevy.com/2010/02/09/getting-started-with-unicorn.html
# and https://github.com/blog/517-unicorn
preload_app true

after_fork do |server, worker|
  ActiveRecord::Base.establish_connection
end

before_fork do |server, worker|
  ##
  # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
  # immediately start loading up a new version of itself (loaded with a new
  # version of our app). When this new Unicorn is completely loaded
  # it will begin spawning workers. The first worker spawned will check to
  # see if an .oldbin pidfile exists. If so, this means we've just booted up
  # a new Unicorn and need to tell the old one that it can now die. To do so
  # we send it a QUIT.
  #
  # Using this method we get 0 downtime deploys.

  old_pid = Rails.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
end

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 heroku unicorn


    【解决方案1】:

    您在这里看到的是预期的。当您通过 dyno 进行扩展时,Heroku 平台会将该 slug 部署到一个新的 dyno 上,该 dyno 与您的其他 dyno(即另一个独角兽大师)完全隔离。

    一旦该 dyno 部署并运行(有效启动),路由网格将开始向该 dyno 发送请求,此时 Rails 将在 Unicorn 或您已设置的任何服务器上启动。

    但是,一旦该请求到达,您有 30 秒的时间返回数据,否则请求将在路由网格上超时(错误 H12)。

    因此,总而言之,您的问题与分叉无关,而是您的应用程序无法在 30 秒内启动,因此提前超时。在 Heroku 平台上不必担心分叉和 PID 文件。

    【讨论】:

    • 嗨,尼尔。解决方案是预加载应用程序,以防止请求进入,直到 dyno(独角兽大师)完全加载应用程序。我关心的是我是否需要before_fork 块中的代码?
    • 你的 before_fork 将一事无成。正如我之前所说,问题在于 Heroku 路由网格将在您的 Unicorn 启动之前向您发送请求。预加载应用程序不会解决此问题。
    • 如果是这样的话。在 Heroku 上旋转/扩展新的 web dyno 时如何防止超时错误发生?
    • 在 30 秒内旋转是唯一的方法。
    • 这不是很有帮助。看来,当您使用 Thin 时,Heroku 会等到新的 dyno 服务器准备好后再向它发出请求。使用 Unicorn,它会在 Unicorn 准备好之前发送请求,因此请求需要 30 多秒,Heroku 无助地杀死了它。必须有办法为 Unicorn 解决这个问题。
    【解决方案2】:

    只是部分答案,但我能够使用此 Unicorn 配置减少这些令人讨厌的缩放超时:

    worker_processes 3 # amount of unicorn workers to spin up
    timeout 30         # restarts workers that hang for 30 seconds
    preload_app true
    
    # hack: traps the TERM signal, preventing unicorn from receiving it and performing its quick shutdown.
    # My signal handler then sends QUIT signal back to itself to trigger the unicorn graceful shutdown
    # http://stackoverflow.com/a/9996949/235297
    before_fork do |_server, _worker|
      Signal.trap 'TERM' do
        puts 'intercepting TERM and sending myself QUIT instead'
        Process.kill 'QUIT', Process.pid
      end
    end
    
    # Fix PostgreSQL SSL error
    # http://stackoverflow.com/a/8513432/235297
    after_fork do |server, worker| 
      defined?(ActiveRecord::Base) and 
      ActiveRecord::Base.establish_connection 
    end
    

    另外,我使用heroku labs:enable preboot(参见https://devcenter.heroku.com/articles/labs-preboot/)。不幸的是,我在扩展 web dynos 时仍然看到一些超时。

    这是我在 HireFire 支持论坛中发起的讨论:http://hirefireapp.tenderapp.com/discussions/problems/205-scaling-up-and-down-too-quickly-provoking-503s

    【讨论】:

    • 遵循相同的方法,它没有帮助。似乎即使有预加载,在 Unicorn 开始“侦听”和分叉的工作人员“准备好”之间也有延迟,对我来说这是 >30 秒,所以即使有所有 预启动,我也会得到 H12错误。
    【解决方案3】:

    preload_app true 为我们的应用程序提供了帮助,所以如果您在部署/重启期间遇到超时问题,请尝试一下。 cmets 说它没有帮助让我认为它不值得尝试,然后意识到这确实是我们需要的修复。

    我们的情况是使用 preboot 的 Rails 应用程序启动缓慢。在某些部署和重新启动时,我们会遇到很多超时,以至于我们的正常运行时间监控认为该站点已关闭。

    我们意识到,使用preload_app false,Unicorn 将首先绑定其端口,然后加载应用程序。一旦绑定端口,Heroku 就会开始向其发送流量。但是,加载这个缓慢的应用程序需要很长时间,因此流量会超时。

    这很容易验证,方法是在 dev 中运行 Unicorn,尝试在启动 Unicorn 后立即访问该站点,并检查您是否收到“该端口上没有服务器”类型错误(理想)或非常慢的请求(不理想) )。

    当我们改为设置preload_app true 时,Unicorn 绑定端口需要更长的时间,但一旦绑定并且 Heroku 向其发送流量,它就可以响应了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-16
      • 2015-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多