Pitchfork sta usando troppa memoria?

Qualcuno vede lo stesso problema? È un forum piuttosto modesto per dimensioni e traffico. Ci sono quattro processi worker di pitchfork, e sembra che uno di essi gestisca la grande maggioranza delle richieste in ingresso e stia utilizzando più memoria rispetto agli altri. C’è un uso elevato della swap, e respawnando deliberatamente pitchfork questo si riduce considerevolmente. Quindi concludo che i processi pitchfork hanno molte pagine fredde attualmente scambiate (swapped out).

Questo è dopo 20 giorni di funzionamento, su una macchina con 4G di RAM e 4G di swap.

Non sarebbe buona cosa esaurire la swap. Non sarebbe buona cosa scoprire che tutta quella swap viene ripaginata in memoria, come potrebbe accadere quando pitchfork alla fine esegue una raccolta dei rifiuti (garbage collect).

Qualcuno vede qualcosa di simile? Condividete la configurazione della macchina, per favore!

# ps aux | sort -n -k 4 | egrep pitchf\|MEM |tail
root     2167652  0.0  0.0   5912  1792 pts/0    S+   20:07   0:00 grep -E --color=auto pitchf|MEM
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000       15094  0.0  0.2 497544 10988 ?        Sl   Jul28   0:17 pitchfork monitor - 
1000       15704  0.0  2.5 6799124 97836 ?       Sl   Jul28   1:00 pitchfork (gen:0) service - ready
1000       15097  0.0  4.8 6791252 189724 ?      Sl   Jul28   5:26 pitchfork (gen:0) mold - ready
1000       15959  0.0  8.1 6815508 319708 ?      Sl   Jul28  12:05 pitchfork (gen:0) worker[3] - requests: 6684, waiting
1000       15900  0.0  9.2 6864596 360696 ?      Sl   Jul28  17:43 pitchfork (gen:0) worker[2] - requests: 14756, waiting
1000       15795  0.1 10.3 6884756 405420 ?      Sl   Jul28  48:36 pitchfork (gen:0) worker[1] - requests: 97007, waiting
1000       15734  2.1 12.8 11299708 500120 ?     Sl   Jul28 637:50 pitchfork (gen:0) worker[0] - requests: 2229848, waiting

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1874636       98840      678812     1931492     1160916
Swap:        4194288     1226600     2967688


# vmstat 5 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0 1226600 115820  65288 1866284    1    1    20    38    0    3  3  1 97  0  0
 0  0 1226600 113208  65296 1866296    0    0     0    14  411  478  1  1 98  0  0
 0  0 1226600 112956  65304 1866336    0    0     1    23  438  528  2  1 97  0  0
 0  0 1226600 112704  65308 1866360    0    0     1    31  518  603  5  1 94  0  0
 0  0 1226600 112704  65308 1866364    0    0     0    11  347  387  1  1 98  0  0

L’output di vmstat mostra che al momento non c’è pressione sulla memoria: nessuna attività di paging. La mia preoccupazione è che esista un pericolo, non che la mia installazione stia funzionando male in questo momento.

cpu0

Per una nota più seria, quello che fa tutto il lavoro ha solo 100 MB di RSS in più rispetto alla media? Mi sembra normale, o sto sbagliando qualcosa?

Mi piacerebbe vedere le statistiche di un forum più attivo. Sembra che il numero cumulativo di richieste sia importante, e il mio non è per niente molto affollato.

Sì, le differenze di RSS sono relativamente modeste, ma passando da 300M a 500M la differenza è piuttosto significativa in termini proporzionali.

Ancora più evidente è l’utilizzo dello swap. Prima di riciclare, ecco cosa vedo:

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1888140       77308      679004     1939520     1147220
Swap:        4194288     1226344     2967944

e dopo:

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1486412     1422380      640744      996176     1587908
Swap:        4194288      309892     3884396

A mio avviso, il riciclo ha liberato circa 1300M (differenza tra used+swap).

Non credo di aver mai visto la necessità di così tanto swap quando usavo unicorn: da qui il titolo.

Come dicevo, sarei interessato a vedere i numeri di altre istanze.

È normale che un processo pitchfork gestisca la maggior parte del carico: gli altri processi vengono selezionati solo quando il primo è occupato. È anche normale che la memoria cresca nel tempo. Sebbene dovrebbe raggiungere uno stato stazionario una volta che tutto, come le cache e ruby-JIT, è stato “scaldato”.

Ecco un grafico da uno dei nostri cluster di produzione, relativo a un periodo di 7 giorni. Questo traccia il singolo processo con il maggiore utilizzo di memoria. Le linee verdi tratteggiate indicano i deploy (cioè gli avvi freschi di pitchfork):

Quindi si può vedere che la memoria cresce dopo l’avvio iniziale, ma poi si stabilizza a poco meno di 1,4 GB. Questo cluster serve centinaia di siti, quindi forse non è il miglior paragone in termini di numeri… ma si spera che la visualizzazione della crescita sia utile.

Guardare i numeri RSS per processo non racconta la storia completa. Pitchfork è un “forking web server”. Quindi avvia il processo “mold” (modello) e poi tutti i worker vengono forkati da questo con uno schema di memoria copy-on-write. Quindi, anche se l’RSS potrebbe mostrare 500 MB per worker[0], circa 200 MB di quella quantità sono condivisi con il mold e tutti gli altri worker.

In un futuro non troppo lontano, speriamo di abilitare la funzione “reforking” di Pitchfork. Elimina periodicamente i worker e li riforca da un worker già scaldato, in modo che condividano la massima quantità di memoria possibile nel tempo. Tuttavia, è necessario un po’ di lavoro per assicurarsi che tutto il nostro codice sia compatibile con quel tipo di schema :crossed_fingers:

Visualizzazione utile, grazie. Non direi che si sia stabilizzato, ma il tasso di crescita non è più così elevato come prima.

Il riforking periodico sembra un’ottima cosa da implementare: se puoi, ti prego di segnalarlo qui quando verrà rilasciato.

Puoi dirmi qualcosa sulle linee verdi? Mi interessa sapere quando (se mai) i pitchfork eseguono una raccolta dei rifiuti, cosa la causa e qual è l’effetto mentre è in corso.

Le linee verdi indicano i momenti in cui effettuiamo il deploy degli aggiornamenti. In pratica: ./launcher rebuild app.

Ruby (e JS, che eseguiamo all’interno dei processi Ruby tramite MiniRacer/v8) esegue continuamente la garbage collection durante l’esecuzione e in risposta ai segnali del sistema operativo. Pertanto, non credo che ci siano grandi vantaggi nel farlo manualmente.

Grazie. Sarei interessato a vedere come si evolvono le cose a lungo termine, il che non sarà evidente su un server che viene aggiornato relativamente spesso. Nel mio caso, ho avuto 20 giorni, poi ho scelto di usare pitchfork per riavviare, il che mi ha dato un’informazione ma ha anche azzerato il timer.