Rails, Passenger e VMSize

Salve lista,

Versione breve:

Come posso abbassare il footprint di memoria di un’applicazione Rails?
Se ci sono delle best pratice, e da cosa dipende l’uso di memoria:
quantit di modelli, quantit di query…

Versione lunga:

sto lavorando da qualche mese ad un progetto Rails che gira in
produzione in questo ambiente:

  • VPS OpenVZ
  • Linux Gentoo
  • Ruby 1.8.7 (2010-01-10 patchlevel 249)
  • Apache 2.2.4 MPM worker
  • Passenger 2.2.15 smart-lv2
  • Rails 2.3-stable
  • Rails plugin e gem a pacchi, molte da git, tra cui prawn, formtastic,
    activescaffold, rubyvis, rmagick, paperclip, class-table-inheritance,
    cancan, breadcrumbs_on_rails, delocalize, globalize2, render_component

Da un po’ di tempo ad intervalli variabili da 2-4 ore a 2-4 giorni tutto
passenger si ferma, i processi di passenger (ApplicationPool, spawn
server, ApplicationSpawner, e workers) sembrano essere OK ma
semplicemente non rispondono, esaminando con strace sembrano attendere
in read indefinitamente senza fare niente quando ricevono richieste
HTTP.

Per anni tutto ha funzionato correttamente, mai uno stop di passenger.

L’evento scatenante sembra essere stato il passaggio da ruby 1.8.6 a
1.8.7 oppure il fatto che ho messo in produzione l’applicazione di cui
sopra che da passenger-memory-stats dice di occupare tantissimo:

VMSize=196.7 MB Private=150.8 MB

Tantissimo visto che Redmine dice di occupare meno della met.

Non sembra essere un problema di risorse esaurite perch il VPS segnala
che i limiti non vengono raggiunti.

Facendo dei test con ab2 tutto risponde bene ad un accettabile livello
di performance sul tempo di risposta e sulla concorrenza.

Ormai ho rinunciato a capire perch Passenger smette di rispondere ed ho
messo nagios a controllare e riavviare.

Il supporto di passenger sembra segnalare tantissimi utenti che hanno
problemi simili senza soluzione

Domande:
1- Avete applicazioni che occupano cos tanto?
2- Sapete come ridurne il footprint?
3- Avete passenger che si riavviano cos spesso?

Grazie,
Antonio B.

2011/5/16 Antonio B. [email protected]:

Domande:
1- Avete applicazioni che occupano cos tanto?

Si, decisamente. 200M non sono necessariamente tanti, e la valutazione
se sia tanto o poco dipende da quanta memoria hai / quanti worker
passenger. Se hai una footprint di 200M, 8 processi e 4G la memoria
non e’ un problema.

2- Sapete come ridurne il footprint?

Profilando l’occupazione di memoria, cerca rails memory profiling.
Anche se non e’ necessariamente un problema, in linea di massima
ridurre la footprint e’ meglio, dato che meno memoria occupi piu’ le
risposte saranno veloci, per via della vituperata garbage collection
di ruby.

3- Avete passenger che si riavviano cos spesso?

Da come dici, non sembra che si riavviino, sembra piuttosto che si
blocchino il che e’ molto diverso! se sei su apache, potresti provare
a giocare con la direttiva PassengerMaxRequests
(Phusion Passenger users guide, Apache version)
che fa si che i singoli worker vengano riavviati dopo n richieste.
Parti con 50, se il problema non si presenta piu’ vuol dire che sono i
singoli processi che si impicciano, se invece si presenta ancora vuol
dire che e’ passenger stesso, ovvero il processo responsabile di
gestire i worker. In quel caso puoi provare ad aggiornarlo, in alcuni
casi funziona (in altri peggiora le cose, almeno una volta mi e’
capitato, mentre una versione ancora successiva rimetteva le cose a
posto)… anche la direttiva SpawnMethod ha un impatto enorme: il
metodo conservativo funziona in piu’ casi, ma se hai parecchio carico
il tempo per startare n worker puo’ diventare piu’ di quanto i client
sono disposti ad aspettare.

Se invece usi nginx, puoi determinare comunque un riavvio dopo n
richieste in questo modo:

in ApplicationController metti una after filter di questo tipo:

after_filter(:expire_process)

a poi il corrispondente metodo

after_filter che fa terminare il processo dopo un certo numero di

richieste
def expire_process
$served_requests = ($served_requests || 0) + 1
if $served_requests >= REQUEST_LIMIT_FOR_AUTO_SHUTDOWN
# logger.debug “Process #{ Process.pid } ha raggiunto il limite,
si manda #{ AUTO_SHUTDOWN_SIGNAL }”
Process.kill AUTO_SHUTDOWN_SIGNAL, Process.pid
end
end

In environment.rb ho definito le due costanti usate:

REQUEST_LIMIT_FOR_AUTO_SHUTDOWN = 50

In genere e’ USR1

AUTO_SHUTDOWN_SIGNAL = :USR1

Ciao

Grazie Luca per la risposta dettagliata ed i consigli,

Ho:

PassengerMaxRequests 20

quindi credo sia un problema di Passenger che smette di funzionare.

Aggiornare la versione vorrebbe dire passare alla serie 3.x che da
quello che si legge sul loro supporto sembra presentare questi ed altri
problemi, anche se prima o poi dovr provare.

Tempo fa avevo provato:

RailsSpawnMethod conservative

ma non cambiava il problema.

Il 16/05/2011 12:26, Luca De Marinis ha scritto:

Parti con 50, se il problema non si presenta piu’ vuol dire che sono i
singoli processi che si impicciano, se invece si presenta ancora vuol
dire che e’ passenger stesso, ovvero il processo responsabile di
gestire i worker. In quel caso puoi provare ad aggiornarlo, in alcuni
casi funziona (in altri peggiora le cose, almeno una volta mi e’
capitato, mentre una versione ancora successiva rimetteva le cose a
posto)
Aggiornato Passenger a 3.0.7 funziona da pi di una settimana e credo
che non si fermer pi: mi tornato a funzionare come facevano le
vecchie versioni di Passenger su Ruby 1.8.6.

L’aggiornamento e lo switch tra diverse versioni di Passenger anche
molto facile senza compilcarsi la vita con i package manager di sistema:
basta installare la versione che si vuole via gem e poi cambiare in
Apache il percorso in cui installata la gem.

Saluti,
Antonio B.