Il processo cron di Garbage Collection di Ubuntu per le sessioni PHP richiede 25 minuti per essere eseguito, perché?


13

Ubuntu ha un cron job impostato che cerca ed elimina le vecchie sessioni PHP:

# Look for and purge old sessions every 30 minutes
09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] \
   && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 \
   -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir \
   fuser -s {} 2> /dev/null \; -delete

Il mio problema è che l'esecuzione di questo processo richiede molto tempo, con un sacco di I / O su disco. Ecco il mio grafico di utilizzo della CPU:

Grafico di utilizzo della CPU

La corsa di pulizia è rappresentata dai picchi dell'alzavola. All'inizio del periodo, i lavori di pulizia di PHP erano programmati alle ore predefinite di 09 e 39 minuti. Alle 15:00 ho rimosso i 39 minuti di cron, quindi un lavoro di pulizia due volte più grande viene eseguito la metà delle volte (puoi vedere che i picchi diventano due volte più larghi e la metà più frequenti).

Ecco i grafici corrispondenti per il tempo di I / O:

Tempo IO

E operazioni su disco:

Operazioni su disco

Al picco in cui erano attive circa 14.000 sessioni, si può vedere che la pulizia è in esecuzione per 25 minuti interi, apparentemente usando il 100% di un core della CPU e quello che sembra essere il 100% dell'IO del disco per l'intero periodo. Perché è così intenso in termini di risorse? Una lsdirectory della sessione /var/lib/php5richiede solo una frazione di secondo. Allora perché ci vogliono 25 minuti interi per tagliare le vecchie sessioni? C'è qualcosa che posso fare per accelerare questo?

Il filesystem per questo dispositivo è attualmente ext4, in esecuzione su Ubuntu Precise 12.04 64-bit.

EDIT: sospetto che il carico sia dovuto al processo insolito "fuser" (dal momento che mi aspetto che un semplice rmsia uno spettacolo dannatamente più veloce delle prestazioni che sto vedendo). Ho intenzione di rimuovere l'uso del fusore e vedere cosa succede.


Quanto traffico arriva al tuo sito Web per generare così tante sessioni?
Michael Hampton

Risposte:


9

La rimozione di fuserdovrebbe aiutare. Questo lavoro esegue un fusercomando (controlla se un file è attualmente aperto) per ogni file di sessione trovato , che può facilmente richiedere diversi minuti su un sistema occupato con 14k sessioni. Questo era un bug di Debian (Ubuntu si basa su Debian).

Invece di memcached puoi anche provare a usare tmpfs (un filesystem in memoria) per i file di sessione. Come memcached questo invaliderebbe le sessioni al riavvio (questo può essere risolto eseguendo il backup di questa directory da qualche parte nello script di spegnimento e ripristinando nello script di avvio), ma sarà molto più facile da configurare. Ma non aiuterà con il fuserproblema.


Sembra che il bug nel fusore fosse che una versione precedente è stata biforcuta ma poi non è stata mai raccolta al termine, lasciando migliaia di fuserprocessi in uno stato di zombi che consumano memoria, il che porta a un crash del server. Penso che sia già stato corretto nella versione di psmisc che sto usando.
thenickdude,

Questo è un altro bug. Hai un semplice problema di avviare migliaia di fuserprocessi, che tutti devono cercare nel /proc/file intero .
Tometzky,

9

Congratulazioni per avere un sito Web popolare e riuscire a mantenerlo in esecuzione su una macchina virtuale per tutto questo tempo.

Se sei veramente tirando in due milioni di pagine viste al giorno, allora si sta andando a impilare un sacco di sessioni PHP nel filesystem, e che stanno andando a prendere molto tempo per eliminare non importa se si utilizza fusero rmo un aspirapolvere.

A questo punto ti consiglio di cercare modi alternativi per memorizzare le tue sessioni:

  • Un'opzione è memorizzare le sessioni inmemcached . Questo è velocissimo, ma se il server si arresta in modo anomalo o si riavvia, tutte le sessioni vengono perse e tutti vengono disconnessi.
  • È inoltre possibile memorizzare sessioni in un database. Questo sarebbe un po 'più lento di memcached, ma il database sarebbe persistente e potresti cancellare le vecchie sessioni con una semplice query SQL. Per implementare questo, però, devi scrivere un gestore di sessioni personalizzato .

Memcached è certamente un'opzione, anche se dovrebbe essere un pool separato dalla nostra istanza memcached principale, altrimenti le sessioni verrebbero sfrattate casualmente dalla nostra pressione della cache. Tuttavia, non sono convinto che la cancellazione di 14.000 file dovrebbe richiedere 25 minuti. Mi sembra troppo lento. Aspetterò un paio d'ore e vedrò com'è la performance di un semplice rm.
thenickdude,

Senza sapere di più sulla tua architettura complessiva, esito a raccomandare l'uno sull'altro.
Michael Hampton

È possibile raggruppare i server Memcached per la ridondanza impostando memcache.session_redundancy = 2. Vedi serverfault.com/questions/164350/… . Redis è una buona opzione se sei preoccupato per la persistenza e molto più veloce degli archivi di database SQL.
jfountain,

4

Pertanto, le opzioni di memorizzazione della sessione Memcached e del database suggerite dagli utenti qui sono entrambe buone scelte per aumentare le prestazioni, ognuna con i propri vantaggi e svantaggi.

Ma dai test delle prestazioni, ho scoperto che l'enorme costo delle prestazioni di questa sessione di manutenzione è quasi interamente dovuto alla chiamata fusernel cron job. Ecco i grafici delle prestazioni dopo il ripristino del processo cron Natty / Oneiric che utilizza rminvece di fusertagliare le vecchie sessioni, il passaggio avviene alle 2:30.

uso della CPU

Tempo di I / O trascorso

Operazioni su disco

Si può vedere che il degrado periodico delle prestazioni causato dalla pulizia della sessione PHP di Ubuntu è quasi completamente rimosso. I picchi mostrati nel grafico delle operazioni del disco sono ora molto più piccoli di grandezza e circa quanto magri può essere misurato da questo grafico, mostrando una piccola, breve interruzione in cui in precedenza le prestazioni del server erano significativamente ridotte per 25 minuti. L'utilizzo extra della CPU è stato completamente eliminato, questo è ora un lavoro associato a IO.

(un processo IO non correlato viene eseguito alle 05:00 e il processo CPU viene eseguito alle 7:40 che entrambi causano i propri picchi su questi grafici)

Il cron job modificato che sto eseguendo è:

09 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && \
   [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 \
   -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -print0 \
   | xargs -n 200 -r -0 rm

-print0 | xargs ...non è necessario: potresti semplicemente andartene -delete. Funzionerà in entrambi i modi con una velocità comparabile.
Tometzky,

1

Mi sono imbattuto in questo post quando ho fatto delle ricerche sulle sessioni. Mentre la risposta accettata è molto buona (e la chiamata del fusore è stata rimossa dallo script gc per qualche tempo) penso che valga la pena notare alcune altre considerazioni se qualcun altro dovesse imbattersi in un problema simile.

Nello scenario descritto, l'OP utilizzava ext4. Le directory in ext4 memorizzano i dati dei file in un formato di database htree, il che significa che vi è un impatto trascurabile nel mantenere molti file in una singola directory rispetto alla distribuzione in più directory multiple. Questo non è vero per tutti i filesystem. Il gestore predefinito in PHP ti consente di utilizzare più sottodirectory per i file di sessione (ma tieni presente che dovresti verificare che il processo di controllo ricorra in quelle directory - il cron job sopra non lo fa).

Gran parte del costo dell'operazione (dopo aver rimosso la chiamata al fusore) deriva dalla ricerca di file non ancora obsoleti. L'uso (ad esempio) di un singolo livello di sottodirectory e 16 lavori cron che guardano in ogni sottodirectory (0 /, 1 /, ... d /, e /, f /) appianeranno i dossi del carico.

L'uso di un gestore di sessioni personalizzato con un substrato più veloce sarà di aiuto, ma c'è molto da scegliere (memcache, redis, mysql handler socket ...) lasciando da parte l'intervallo in termini di qualità di quelli pubblicati su Internet, che scegli dipende dall'esatto requisiti relativi all'applicazione, all'infrastruttura e alle competenze, per non dimenticare che spesso ci sono differenze nella gestione della semantica (in particolare il blocco) rispetto al gestore predefinito.


0

Con quel tipo di traffico non dovresti mettere sessioni in dis. Dovresti usare qualcosa come memcache. Tutto quello che devi fare è impostare php e non sarà necessario cambiare il codice. Vedi per esempio

http://www.dotdeb.org/2008/08/25/storing-your-php-sessions-using-memcached/

Il motivo per cui sta impiegando così tanto tempo è dovuto alla grande quantità di file che deve ordinare per vedere quali possono essere eliminati. Memcache può scadere automaticamente in base alla durata della sessione impostata nel codice.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.