2012-02-18 4 views
7

Podczas korzystania z Unicorn na Heroku. Skalowanie, będzie miało problemy, ponieważ nowe skalowalne dyna internetowe mogą być dostępne przez żądanie, gdy wciąż ładuje aplikację. Co zwykle powoduje błąd limitu czasu.Czy poprawnie ładuję aplikację w Heroku + Unicorn?

Zrobiłem trochę czytania w http://codelevy.com/2010/02/09/getting-started-with-unicorn.html i https://github.com/blog/517-unicorn

dwóch artykułów zasugerował użycie preload_app true. I blok after_fork i before_fork.

W Railsach 3+, czy kod w before_block jest nadal wymagany? Czytałem gdzieś, w przeciwnym razie. Ktoś, kto doświadczył już wcześniej tego ustawienia i chciałby się z nami podzielić?

Czy brakuje mi czegoś jeszcze? Czy poprawnie ładuję aplikację?

# 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 

Odpowiedz

2

To, co tu widzisz, jest spodziewane. W momencie skalowania przez dynię, platforma Heroku wprowadzi ten ślimak do nowego dyna, który jest całkowicie odizolowany od innych dynosów (to znaczy innego mistrza jednorożca).

Po wdrożeniu i uruchomieniu dyno (efektywnie uruchomione), sieć routingu rozpocznie wysyłanie żądań do tej dyno, czyli kiedy Railsy uruchomią się na Unicorn, czy jak tam, na serwerze, który masz skonfigurowany.

Po otrzymaniu tego żądania masz jednak 30-sekundowe okno do zwrócenia danych lub upłynie limit czasu żądania na siatce routingu (błąd H12).

Dlatego, aby podsumować, Twój problem nie dotyczy rozwidlenia, ponieważ twoja aplikacja nie może się uruchomić w ciągu 30 sekund, stąd wczesne limity czasu. Martwienie się o rozwidlanie i pliki PID nie jest czymś, o co musisz się martwić na platformie Heroku.

+0

Cześć Neil. Rozwiązaniem jest wstępne załadowanie aplikacji, aby zapobiec przychodzeniu żądań, dopóki dyno (mistrz jednorożca) nie załaduje aplikacji w pełni. Moje obawy tutaj jest, czy potrzebuję kod w bloku 'before_fork'? –

+0

Twoja before_fork nic nie da. Jak już wcześniej wspomniałem, problem polega na tym, że sieć rutowania Heroku będzie wysyłać ci prośby, zanim Twój jednorożec się zacznie. Wstępne załadowanie aplikacji nie rozwiąże problemu. –

+0

Jeśli tak jest. W jaki sposób uniknąć błędów limitu czasu podczas obracania/skalowania nowych dynamo internetowych na Heroku? –

1

Tylko odpowiedź częściową, ale byli w stanie zmniejszyć te paskudne timeoutów skalowania z tym Unicorn konfiguracją:

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 

Również używam heroku labs:enable preboot (patrz https://devcenter.heroku.com/articles/labs-preboot/). Niestety nadal widzę pewne przekroczenia czasu podczas skalowania dynamicznych sieci.

Oto dyskusja na forum wsparcia HireFire, rozpocząłem: http://hirefireapp.tenderapp.com/discussions/problems/205-scaling-up-and-down-too-quickly-provoking-503s

+0

Po tym samym podejściu i to nie pomaga. Wygląda na to, że nawet przy wstępnym ładowaniu występuje opóźnienie między momentem, w którym Unicorn zaczyna "słuchać", a gdy rozwidleni pracownicy są "gotowi", dla mnie jest to> 30 sekund, więc nawet przy tym wszystkim * i * przed uruchomieniem otrzymuję błędy H12. –

1

preload_app true pomógł dla naszej aplikacji, więc nie dać mu szansę, jeśli widzisz problemy z limity czasu podczas deploy/reboot. Komentarze, które mówią, że to nie pomaga, sprawiły, że myślę, że nie warto próbować, a potem uświadomiłem sobie, że rzeczywiście potrzebujemy tej poprawki.

Nasza sytuacja polegała na powolnym uruchamianiu aplikacji Rails przy użyciu preboot. W przypadku niektórych wdrożeń i ponownych uruchomień uzyskamy wiele limitów czasu, do tego stopnia, że ​​witryna została uznana za przestarzałą przez nasz monitoring czasu pracy.

Uświadomiliśmy sobie, że z preload_app false, Unicorn najpierw zwiąże swój port, a następnie załaduje aplikację. Zaraz po związaniu portu Heroku rozpoczyna wysyłanie ruchu. Jednak opóźnienie w załadowaniu tej powolnej aplikacji zajmuje trochę czasu, więc ruch uzyskuje limity czasu.

Łatwo to sprawdzić, uruchamiając Unicorn w dev, próbując uzyskać dostęp do strony zaraz po uruchomieniu Unicorn i sprawdzając, czy otrzymujesz błąd typu "brak serwera na tym porcie" (pożądany) lub bardzo powolne żądanie (nie pożądany).

Kiedy zamiast tego ustawimy , to będzie trwało dłużej, dopóki Unicorn nie połączy portu, ale gdy to zrobi, a Heroku wyśle ​​ruch, będzie gotowy do odpowiedzi.