¿Cómo debo manejar los archivos de sesión que se vuelven demasiado numerosos?

43

Actúo como administrador de sistemas para un par de servidores que contienen sitios de Magento y ocasionalmente se llenan con archivos de sesión.

Me han dicho que administrar estos archivos no es algo que se pueda hacer desde Magento y supongo que su uso temporal significa que no se pueden desactivar, pero parece extraño que Magento no tenga forma de eliminarlos. archivos?

Mi solución es un crontab nocturno que realiza algo como esto find /path/to/magento/sessions/ -name "sess*" -type f -deletepero se siente poco elegante por decir lo menos.

¿Cuál es la mejor manera de manejar esto?

Toby
fuente

Respuestas:

37

Además de eliminar archivos de sesión con el finduso de un tiempo de modificación personalizado como lo mencionan otros, también puede:

  • Guarde las sesiones en su base de datos . Por supuesto, esto cargará su base de datos y no es la forma más rápida, pero puede manejar muchas más sesiones de esa manera y puede compartir sesiones entre múltiples servidores frontend. Puede cambiar la configuración app/etc/local.xmlcambiando

    <session_save><![CDATA[files]]></session_save>

    a

    <session_save><![CDATA[db]]></session_save>
  • Use memcached como su almacenamiento de sesión. Magento también admite esto de forma predeterminada. Echa un vistazo a app/etc/local.xml.additionalla configuración. Nunca lo usé en producción, pero he oído que esto puede ser un poco complicado.

  • Maneje las sesiones en Redis usando la extensión brillante Colin Mollenhours Cm_RedisSession . La configuración de Redis no debería demorar demasiado, también se puede usar para el almacenamiento en caché (consulte Cm_Cache_Backend_Redis ) y combina una memoria caché de RAM con persistencia en el disco (en oposición a memcached, discos RAM o similares), que siempre está en caso de que su servidor esté chocando

Matthias Zeis
fuente
1
Guardar las sesiones en la base de datos también es más seguro. Si su archivo .htaccess no está allí (porque alguien eliminó la carpeta var), sus archivos de sesión no serán accesibles desde el exterior.
Erfan
8
Guardar las sesiones en la base de datos es una mala idea. No está diseñado para ese propósito y MySQL sirve como una herramienta muy pobre para el almacenamiento de sesiones, el bloqueo es un problema clave, sin mencionar que no hay soporte incorporado para la purga.
Ben Lessani - Sonassi
28

Con las sesiones basadas en archivos, el cron de limpieza de sesión de PHP las podará automáticamente, por lo que es probable que los archivos se eliminen dentro de ~ 7200 segundos de la creación. Entonces, incluso en un sitio ocupado (30k únicos por día), generalmente solo hay alrededor de 4,000 archivos de sesión en ./var/session, lo que no es nada incluso para un servidor Linux de gama baja.

Sin embargo, la limpieza en realidad se basa en el funcionamiento cron, que normalmente no se ve en el directorio ./var/session de Magento. Entonces deberías configurar un nuevo sistema cron

/usr/bin/find /home/myuser/public_html/var/session -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -print0 -exec rm {} \; >/dev/null 2>&1

El período de limpieza predeterminado para las sesiones es de 7200 segundos, que debería ser más que adecuado, aunque puede cambiar lo anterior para adaptarlo.

Con las sesiones de Memcache, TCP / IP es la única sobrecarga, que para una implementación de servidor único, lo haría más lento que el basado en archivos. Entonces, usaría un zócalo Unix, que elimina esa sobrecarga y brinda una mejor seguridad. Pero aún así, sus sesiones de cliente se truncarán / limitarán en cuanto a la cantidad de RAM que puede asignar. La sesión promedio de Magento es de 4Kb, por lo que podrá admitir 256 sesiones activas, por MB que asigne. Por lo tanto, asegúrese de establecer un límite apropiado para evitar que los clientes pierdan el carrito / sesión al azar. Y también ten en cuenta que un reinicio del demonio Memcache eliminará todas las sesiones existentes (¡MALO!).

Con Redis (no nativo, pero disponible a través de una extensión), obtienes un nivel de soporte similar al de Memcache, pero con los beneficios adicionales de la persistencia (si deseas usarlo). Con la extensión Cm_Redis, también podrá aprovechar la compresión de sesión. Hemos descubierto que esta extensión funciona muy bien tanto en implementaciones de CE como de EE.

Con DB, la configuración predeterminada de caducidad de la ciruela pasa es una semana poderosa, por lo que con el tamaño de la tienda anterior como ejemplo (30k únicos por día), verá un tamaño de tabla de base de datos para core_cache_session de alrededor de 7GB, lo que será una rutina su tienda se detiene por completo, para casi todas las operaciones basadas en sesiones.

Por la experiencia de alojar tiendas grandes (230k visitantes únicos por día) y pequeñas (<1k visitantes únicos por día), nuestra recomendación es:

Implementación de servidor único: archivos

Implementación multiservidor: Redis (utilizando una base de datos separada del caché principal de Magento)

Escribí algunas respuestas realmente completas aquí http://magebase.com/magento-tutorials/magento-session-storage-which-to-choose-and-why/comment-page-1/#comment-1980

Ben Lessani - Sonassi
fuente
2
Si se supone que el cron de limpieza borra las sesiones, ¿por qué falla y cómo se puede solucionar ese problema en lugar de crear un nuevo cron que parezca una solución?
Ganso
12

He hecho una pregunta relacionada hace algún tiempo:

https://stackoverflow.com/questions/7828975/php-garbage-collection-clarification

Lo que nunca descubrí (dejé ese trabajo por uno nuevo, y el problema original se convirtió en el de otra persona) es si las sesiones de Magento respetarán esta configuración, o si implementan su manejo de sesión usando Zend (y presumiblemente algún tipo de zend.ini archivo de configuración).

La configuración de php para mirar:

session.gc_maxlifetime session.gc_probability session.gc_divisor

http://php.net/manual/en/session.configuration.php#ini.session.gc-probability

pspahn
fuente
Me encantaría saber esto yo mismo, desde mi experiencia parece que Magento no respeta esta configuración (teniendo en cuenta que obtuve el valor de GB de los archivos de sesión, sería seguro asumir que en algún momento GC se habría activado). Así que acabo de configurar el script recomendado por Ben como un trabajo cron para estar seguro.
Javier Villanueva
7

Por lo general, un trabajo cron es suficiente, pero aquí hay algunas cosas a tener en cuenta:

1) Configure la sesión para que no dure más de session.gc_maxlifetime( php -i | grep session.gc_maxlifetime) segundos (esto configurará sesiones expiradas para que php.ini o .htaccess preparen la recolección de basura)

2) Es posible que desee almacenar las sesiones en la base de datos. Consulte aquí para obtener más información sobre cómo hacerlo (esta opción podría ser más fácil de administrar a través del módulo personalizado de magento)

3) Otra opción a considerar es que la bruja Memcached también puede acelerar los servidores (aunque no está completamente conectado a la pregunta, creo que es útil saberlo)

Consulte esta pregunta para obtener más información: https://stackoverflow.com/questions/4353875/how-long-do-the-magento-session-files-need-to-be-kept

pzirkind
fuente
2
Usar un cronjob para simplemente eliminar todos los archivos de sesión es inaceptable. ¿Qué sucede cuando un usuario agrega cosas a su carrito 10 minutos antes de que se ejecute el cron? ¡Su carro está limpio! Si la recolección de basura de PHP no funciona, eso debe ser resuelto.
davidalger
1 @davidalger punto bueno, yo estaba bajo el supuesto (errónea) de que sólo las sesiones expiradas se eliminan a través de cron
pzirkind
1
@davidalger: la propia recolección de basura de PHP funciona a través de cron. Simplemente tiene findtodos los archivos anteriores sess.gc_maxlifetimey los elimina. Eliminar sesiones a través de cron es un comportamiento normal, seguro y aceptable.
Ben Lessani - Sonassi
1
En realidad, no, no lo es. La recolección de basura de sesión se realiza cuando se inicia la sesión durante la ejecución de un script PHP. La frecuencia con la que se ejecuta la recolección de basura depende de los valores de session.gc_probabilityy session.gc_divisor. Si diferentes secuencias de comandos tienen valores diferentes para session.gc_maxlifetimeel que tiene el valor más bajo, determinará cuánto tiempo durará el tiempo ya que el almacenamiento de la sesión es global y la ejecución de esa secuencia de comandos limpiará los otros objetos de sesión de secuencias de comandos.
davidalger
5

En todas nuestras configuraciones tenemos un archivo maintenance.php que se encarga de la limpieza de los registros y el directorio var de vez en cuando. Dado que las sesiones deben guardarse en la base de datos o en el sistema de archivos, este archivo de mantenimiento los limpiará a ambos. (Ver código a continuación).

Puede ejecutar el siguiente comando como un trabajo cron para limpiar los registros:

php maintenance.php clean=log

El comando anterior producirá el siguiente resultado:

catalogindex_aggregation has been truncated
catalogindex_aggregation_tag has been truncated
catalogindex_aggregation_to_tag has been truncated
catalog_compare_item has been truncated
dataflow_batch_export has been truncated
dataflow_batch_import has been truncated
log_customer has been truncated
log_quote has been truncated
log_summary has been truncated
log_summary_type has been truncated
log_url has been truncated
log_url_info has been truncated
log_visitor has been truncated
log_visitor_info has been truncated
log_visitor_online has been truncated
report_compared_product_index has been truncated
report_event has been truncated
report_viewed_product_index has been truncated

Puede ejecutar el siguiente comando como un trabajo cron para limpiar la carpeta var:

php maintenance.php clean=var

El comando anterior producirá el siguiente resultado:

downloader/.cache/* has been emptied
downloader/pearlib/cache/* has been emptied
downloader/pearlib/download/* has been emptied
var/cache/ has been emptied
var/locks/ has been emptied
var/log/ has been emptied
var/report/ has been emptied
var/session/ has been emptied
var/tmp/ has been emptied

El código real (no olvide ajustar la ruta a su archivo local.xml):

<?php
$xml = simplexml_load_file('./app/etc/local.xml', NULL, LIBXML_NOCDATA);

$db['host'] = $xml->global->resources->default_setup->connection->host;
$db['name'] = $xml->global->resources->default_setup->connection->dbname;
$db['user'] = $xml->global->resources->default_setup->connection->username;
$db['pass'] = $xml->global->resources->default_setup->connection->password;
$db['pref'] = $xml->global->resources->db->table_prefix;

if (!isset($argv[1]) || !stristr($argv[1], 'clean=')) {
    echo 'Please use one of the commands below:' . PHP_EOL;
    echo 'php maintenance.php clean=log' . PHP_EOL;
    echo 'php maintenance.php clean=var' . PHP_EOL;
    die;
}

$method = str_replace('clean=', '', $argv[1]);

switch ($method) {
case 'log':
    clean_log_tables();
    break;
case 'var':
    clean_var_directory();
    break;
default:
    echo 'Please use one of the commands below:' . PHP_EOL;
    echo 'php maintenance.php clean=log' . PHP_EOL;
    echo 'php maintenance.php clean=var' . PHP_EOL;
    break;
}

function clean_log_tables() {
    global $db;

    $tables = array(
        'catalogindex_aggregation',
        'catalogindex_aggregation_tag',
        'catalogindex_aggregation_to_tag',
        'catalog_compare_item',
        'dataflow_batch_export',
        'dataflow_batch_import',
        'log_customer',
        'log_quote',
        'log_summary',
        'log_summary_type',
        'log_url',
        'log_url_info',
        'log_visitor',
        'log_visitor_info',
        'log_visitor_online',
        'report_compared_product_index',
        'report_event',
        'report_viewed_product_index'
    );

    mysql_connect($db['host'], $db['user'], $db['pass']) or die(mysql_error());
    mysql_select_db($db['name']) or die(mysql_error());

    foreach($tables as $v => $k) {
        @mysql_query('TRUNCATE `'.$db['pref'].$k.'`');
        echo $db['pref'] . $k . ' has been truncated' . PHP_EOL;
    }
}

function clean_var_directory() {
    $dirs = array(
        'downloader/.cache/*',
        'downloader/pearlib/cache/*',
        'downloader/pearlib/download/*',
        'var/cache/',
        'var/locks/',
        'var/log/',
        'var/report/',
        'var/session/',
        'var/tmp/'
    );

    foreach($dirs as $v => $k) {
        exec('rm -rf '.$k);
        echo $k . ' has been emptied' . PHP_EOL;
    }
}
Kenny
fuente
5

Para Magento CMS y similares (que no están limpiando sesiones antiguas), solo uso trabajos cron basados ​​en la configuración de php.ini.

PHP5 / Ubuntu 14.04 / Debian

La configuración del sistema cron.d para php5 no limpia Magento ./var/session (ni nada aparte de la carpeta de sesión predeterminada (/ var / lib / php5 para Ubuntu y / var / lib / php5 / sessions o / tmp / para la mayoría de los otros Linux) Dists).

Pero aún puede usar "sessionclean" y "maxlifetime" según el cron predeterminado del sistema php5 / Debian:

Ejemplo que puedes probar desde la línea de comando:

# sudo /usr/lib/php5/sessionclean /var/www/{yoursite}/var/session $(/usr/lib/php5/maxlifetime)

Así que simplemente incorpórelo a un crontab de sistema / raíz o a un crontab de usuario que tenga permiso de lectura / escritura para los archivos de sesión:

$ sudo crontab -e

Agregue esto si quiere que se vea similar al sistema php cron:

20,40 * * * * [ -x /usr/lib/php5/maxlifetime ] && [ -x /usr/lib/php5/sessionclean ] && [ -d /var/www/*/var/session ] && /usr/lib/php5/sessionclean /var/www/{yoursite}/var/session $(/usr/lib/php5/maxlifetime)

o - como sabemos que esos archivos / directorios existen:

20,40 * * * * /usr/lib/php5/sessionclean /var/www/*/var/session $(/usr/lib/php5/maxlifetime)

Ahora tengo una cantidad manejable de sesiones y se mantiene limpia a través de la recolección de basura predeterminada / de por vida a través de la configuración de php.ini (cli).

(Puede dejar el comodín arriba o reemplazarlo con el nombre del sitio).

EDITAR (PHP7 / Ubuntu 16.xx / Debian):

El script 'sessionclean' ha cambiado y el script maxlifetime ha sido eliminado. Para el trabajo cron system / php, ahora es un script. Realmente ya no puede usar esto ya que las llamadas al archivo ahora son estáticas para el script.

El script php5 sessionclean anterior aún puede funcionar si el sistema no se está limpiando. Lo que puede hacer es tomar el paquete anterior de Debian php5 y extraerlo sessionclean. O simplemente puede copiar esto en su área de scripts (otorgando los permisos / propiedad / var / www / (site) adecuados):

#!/bin/sh

# first find all used files and touch them (hope it's not massive amount of files)
[ -x /usr/bin/lsof ] && /usr/bin/lsof -w -l +d "${1}" | awk -- '{ if (NR > 1) { print $9; } }' | xargs -i touch -c {}

# find all files older then maxlifetime
find "${1}" -depth -mindepth 1 -maxdepth 1 -ignore_readdir_race -type f -cmin "+${2}" -delete

También recomiendo renombrarlo, para que no se confunda con el nuevo cronjob 'sessionclean' de php. Luego puede insertar su propio número "maxlifetime" de la siguiente manera:

     20,40 * * * * /home/-username-/scripts/MySessionClean /var/www/*/var/session 61

(61 es la edad de ejemplo (en minutos) y 'MySessionClean' es el script php5 renombrado descargado o copiado desde arriba).

De esta manera, evitamos las llamadas php.ini / env por completo.

(EDITAR 13DEC2016: Actualización de DEBIAN ARCHIVE REPO LINK)

bshea
fuente
3

Limpié el DB regularmente de todos estos archivos de sesión antiguos. Fue un trabajo manual irritante hasta que instalé Magento Optimizer, lo que hace que toda esta rutina funcione para mí. Además, mi caché se actualiza constantemente y no lo hago manualmente después de cambiar productos y bloques estáticos. Ah, sí, los informes de errores y los carros abandonados también se limpian.

James
fuente
3

De todos los comentarios anteriores, creo que esta es la solución fácil y espero que sea mejor que los scripts largos y la instalación de extensiones de terceros para administrar archivos de sesiones antiguas y mantener nuevos archivos de sesión.

  1. Cree un nombre de archivo "clean_session.sh" en su magentocarpeta.
  2. Pega estas líneas.

#!/bin/bash
# delete session files older than 14 days
find /home/DOMAIN/public_html/var/session -name 'sess_*' -type f -mtime +14 -exec rm {} \;

  1. Luego puede programar cronjob semanalmente para realizar la limpieza.

1 1 * * 6 /bin/sh /home/DOMAIN/public_html/clean_session.sh

  1. No olvide hacer que el archivo sea ejecutable como

chmod u+x clean_session.sh

  1. Y también puedes ejecutarlo como

sh clean_session.sh

Añil
fuente
3

Para mi caso, ejecuto este script ubicado en el magento/var/directorio para eliminar archivos de sesión de más de una semana ( -mtime +7) de antigüedad:

#!/bin/sh
# Place this script in magento/var/ directory

for n in `seq 0 9`
  do
    for u in `seq 0 9`
    do
      for m in `seq 0 9`
        do
          name="sess_"$n$u$m*
          echo $name
          find session/ -name $name -type f -mtime +7 -delete
          echo $name ok
      done
      for m in {a..z}
        do
          name="sess_"$n$u$m*
          echo $name
          find session/ -name $name -type f -mtime +7 -delete
          echo $name ok
      done
    done
      for u in {a..z}
      do
        for m in `seq 0 9`
          do
            name="sess_"$n$u$m*
            echo $name
            find session/ -name $name -type f -mtime +7 -delete
            echo $name ok
        done
        for m in {a..z}
          do
            name="sess_"$n$u$m*
            echo $name
            find session/ -name $name -type f -mtime +7 -delete
            echo $name ok
        done
    done
done

for n in {a..z}
  do
    for u in `seq 0 9`
      do
        for m in `seq 0 9`
          do
            name="sess_"$n$u$m*
            echo $name
            find session/ -name $name -type f -mtime +7 -delete
            echo $name ok
        done
        for m in {a..z}
          do
            name="sess_"$n$u$m*
            echo $name
            find session/ -name $name -type f -mtime +7 -delete
            echo $name ok
        done
    done
    for u in {a..z}
      do
        for m in `seq 0 9`
          do
            name="sess_"$n$u$m*
            echo $name
            find session/ -name $name -type f -mtime +7 -delete
            echo $name ok
        done
        for m in {a..z}
          do
            name="sess_"$n$u$m*
            echo $name
            find session/ -name $name -type f -mtime +7 -delete
            echo $name ok
        done
    done
done

Es mi primer script de bash (revisión 2) y creo que se puede optimizar en varios aspectos. Estoy abierto a cualquier sugerencia de optimización.

Este script se puede recuperar en: https://gist.github.com/Nolwennig/a75dc2f8628be2864bb2

Nolwennig
fuente
0

Creé un script que vacía el directorio var / session. Puede agregarlo a un trabajo cron para ejecutarlo una vez al día, lo que debería ser suficiente y ajustar según sea necesario. Notarás que cuando el directorio de la sesión se llena, es imposible eliminar archivos a través de cpanel o ssh, este script hará el truco simplemente colocarlo en el directorio raíz de magento.

<?php
function adjustSessionFiles($dir, $pattern = "*")
{
    $files = glob($dir . "/$pattern");
    foreach ($files as $file) {
        if (is_dir($file) and !in_array($file, array('..', '.')))  {
            adjustSessionFiles($file, $pattern);
        }else if(is_file($file) and ($file != __FILE__)) {
            unlink($file);
        }
    }
}
$dir = __DIR__ . DIRECTORY_SEPARATOR . 'var' . DIRECTORY_SEPARATOR . 'session';
adjustSessionFiles($dir);
Lawrence Farbman
fuente
El problema con este script es que elimina todas las sesiones, no solo las antiguas. Por lo tanto, nadie puede iniciar sesión más de un día (si ejecuta esto a diario), y todos los carros estarán vacíos después de que esto se haya ejecutado (por lo que ningún carro retendrá más de un día).
simonthesorcerer