El trabajo cron de recolección de basura de Ubuntu para sesiones PHP tarda 25 minutos en ejecutarse, ¿por qué?

13

Ubuntu tiene un trabajo cron configurado que busca y elimina sesiones PHP antiguas:

# 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

Mi problema es que este proceso está tardando mucho en ejecutarse, con mucho disco IO. Aquí está mi gráfico de uso de CPU:

Gráfico de uso de la CPU

La limpieza en ejecución está representada por las espigas verde azulado. Al comienzo del período, los trabajos de limpieza de PHP se programaron en los tiempos predeterminados de 09 y 39 minutos. A las 15:00, eliminé el tiempo de 39 minutos de cron, por lo que un trabajo de limpieza del doble del tamaño se ejecuta la mitad de las veces (puede ver que los picos se doblan el doble y la mitad de la frecuencia).

Aquí están los gráficos correspondientes para el tiempo IO:

IO time

Y operaciones de disco:

Operaciones de disco

En el pico donde había aproximadamente 14,000 sesiones activas, se puede ver que la limpieza se ejecuta durante 25 minutos completos, aparentemente usando el 100% de un núcleo de la CPU y lo que parece ser el 100% del disco IO durante todo el período. ¿Por qué es tan intensivo en recursos? Una lsde las sesiones del directorio /var/lib/php5toma solo una fracción de segundo. Entonces, ¿por qué se tarda 25 minutos completos en recortar las sesiones antiguas? ¿Hay algo que pueda hacer para acelerar esto?

El sistema de archivos para este dispositivo es actualmente ext4, ejecutándose en Ubuntu Precise 12.04 de 64 bits.

EDITAR: sospecho que la carga se debe al proceso inusual "fusor" (ya que espero que un simple rmsea ​​mucho más rápido que el rendimiento que estoy viendo). Voy a eliminar el uso del fusor y ver qué pasa.

luegoickdude
fuente
¿Cuánto tráfico obtiene su sitio web para generar tantas sesiones?
Michael Hampton

Respuestas:

9

La eliminación de fuserdebería ayudar. Este trabajo ejecuta un fusercomando (verifique si un archivo está abierto actualmente) para cada archivo de sesión encontrado , lo que puede tomar fácilmente varios minutos en un sistema ocupado con 14k sesiones. Este fue un error de Debian (Ubuntu se basa en Debian).

En lugar de memcached, también puede intentar usar tmpfs (un sistema de archivos en memoria) para los archivos de sesión. Al igual que memcached, esto invalidaría las sesiones al reiniciar (esto se puede solucionar haciendo una copia de seguridad de este directorio en algún lugar del script de apagado y restaurando el script de inicio), pero será mucho más fácil de configurar. Pero no ayudará con el fuserproblema.

Tometzky
fuente
Parece que el error en el fusor fue que una versión anterior se bifurcó pero luego nunca se cosechó al finalizar, dejando miles de fuserprocesos en una memoria que consume estado zombie, lo que conduce a un bloqueo del servidor. Creo que eso ya se ha solucionado en la versión de psmisc que estoy usando.
thenickdude
Ese es otro error. Tiene un problema simple de iniciar miles de fuserprocesos, todos los cuales deben buscar /proc/archivos abiertos en el conjunto .
Tometzky
9

Felicitaciones por tener un sitio web popular y lograr mantenerlo funcionando en una máquina virtual durante todo este tiempo.

Si usted está realmente tirando de dos millones de páginas vistas por día, entonces usted va a apilar un montón de sesiones de PHP en el sistema de archivos, y que va a tomar mucho tiempo para eliminar independientemente de si se utiliza fusero rmo una aspiradora.

En este punto, te recomiendo que busques formas alternativas de almacenar tus sesiones:

  • Una opción es almacenar sesiones enmemcached . Esto es rápido como un rayo, pero si el servidor falla o se reinicia, todas sus sesiones se pierden y todos se desconectan.
  • También puede almacenar sesiones en una base de datos. Esto sería un poco más lento que memcached, pero la base de datos sería persistente y podría borrar sesiones antiguas con una simple consulta SQL. Sin embargo, para implementar esto, debe escribir un controlador de sesión personalizado .
Michael Hampton
fuente
Memcached es sin duda una opción, aunque tendría que ser un grupo separado de nuestra instancia principal de memcached, de lo contrario, las sesiones se desalojarían aleatoriamente de nuestra presión de caché. Sin embargo, no estoy convencido de que eliminar 14,000 archivos tome 25 minutos. Eso me suena demasiado lento. Voy a esperar un par de horas y ver cómo es el rendimiento de un simple rm.
thenickdude
Sin saber más acerca de su arquitectura general, dudo en recomendar una sobre la otra.
Michael Hampton
Puede agrupar servidores Memcached para redundancia configurando memcache.session_redundancy = 2. Ver serverfault.com/questions/164350/… . Redis es una buena opción si le preocupa la persistencia y mucho más rápido que los almacenes de bases de datos SQL.
jfountain
4

Por lo tanto, las opciones de almacenamiento de sesión de Memcached y de base de datos sugeridas por los usuarios aquí son buenas opciones para aumentar el rendimiento, cada una con sus propios beneficios e inconvenientes.

Pero mediante las pruebas de rendimiento, descubrí que el enorme costo de rendimiento del mantenimiento de esta sesión se debe casi por completo a la llamada fuseren el trabajo cron. Aquí están los gráficos de rendimiento después de volver al trabajo cron Natty / Oneiric que utiliza en rmlugar de fuserrecortar sesiones antiguas, el cambio ocurre a las 2:30.

uso de CPU

Tiempo transcurrido IO

Operaciones de disco

Puede ver que la degradación periódica del rendimiento causada por la limpieza de la sesión PHP de Ubuntu se elimina casi por completo. Los picos que se muestran en el gráfico de Operaciones de disco ahora son mucho más pequeños en magnitud, y casi tan delgados como este gráfico puede medir, mostrando una pequeña interrupción corta donde anteriormente el rendimiento del servidor se degradó significativamente durante 25 minutos. El uso adicional de CPU se elimina por completo, ahora es un trabajo vinculado a IO.

(un trabajo de E / S no relacionado se ejecuta a las 05:00 y el trabajo de la CPU se ejecuta a las 7:40, lo que causa sus propios picos en estos gráficos)

El trabajo cron modificado que estoy ejecutando ahora es:

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
luegoickdude
fuente
-print0 | xargs ...no es necesario, simplemente puedes irte de -deleteallí. Pero funcionará en ambos sentidos con una velocidad comparable.
Tometzky
1

Me encontré con esta publicación cuando hice algunas investigaciones sobre las sesiones. Si bien la respuesta aceptada es muy buena (y la llamada del fusor se ha eliminado del script gc durante algún tiempo), creo que vale la pena señalar algunas otras consideraciones si alguien más se encuentra con un problema similar.

En el escenario descrito, el OP estaba usando ext4. Los directorios en ext4 almacenan datos de archivos en un formato de base de datos htree, lo que significa que hay un impacto insignificante en mantener muchos archivos en un solo directorio en comparación con distribuirlos en varios directorios. Esto no es cierto para todos los sistemas de archivos. El controlador predeterminado en PHP le permite usar múltiples subdirectorios para los archivos de sesión (pero tenga en cuenta que debe verificar que el proceso de control se repita en esos directorios; el trabajo cron anterior no lo hace).

Gran parte del costo de la operación (después de eliminar la llamada al fusor) surge de mirar archivos que aún no están obsoletos. El uso (por ejemplo) de un solo nivel de subdirectorios y 16 trabajos cron que buscan en cada subdirectorio (0 /, 1 /, ... d /, e /, f /) suavizarán los baches de carga que surjan.

El uso de un controlador de sesión personalizado con un sustrato más rápido ayudará, pero hay mucho para elegir (memcache, redis, mysql handler socket ...) dejando de lado el rango de calidad de los publicados en Internet, que usted elige depende de la exactitud requisitos con respecto a su aplicación, infraestructura y habilidades, sin olvidar que con frecuencia existen diferencias en el manejo de la semántica (especialmente el bloqueo) en comparación con el controlador predeterminado.

symcbean
fuente
0

Con ese tipo de tráfico no debería poner sesiones en desuso. Deberías estar usando algo como memcache. Todo lo que tiene que hacer es configurar php y no será necesario cambiar el código. Ver por ejemplo

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

La razón por la que lleva tanto tiempo se debe a la gran cantidad de archivos que tiene que clasificar para ver cuáles se pueden eliminar. Memcache puede caducar automáticamente, dada la duración de la sesión que configuró en su código.

Miguel
fuente