Como devo lidar com arquivos de sessão que se tornam muito numerosos?

43

Estou atuando como administrador de sistemas para alguns servidores que possuem sites Magento e, ocasionalmente, eles são preenchidos com arquivos de sessão.

Disseram-me que gerenciar esses arquivos não é algo que pode ser feito no Magento e presumo que o uso temporário deles significa que eles não podem ser desativados, mas parece estranho que o Magento não tenha como lidar com a remoção desses arquivos. arquivos?

Minha solução é um crontab noturno que executa algo assim, find /path/to/magento/sessions/ -name "sess*" -type f -deletemas parece deselegante para dizer o mínimo.

Qual é a melhor maneira de lidar com isso?

Toby
fonte

Respostas:

37

Além de excluir arquivos de sessão findusando um horário de modificação personalizado, conforme mencionado por outros, você também pode:

  • Salve as sessões no seu banco de dados . É claro que isso sobrecarregará seu banco de dados e não é o caminho mais rápido, mas você pode lidar com mais sessões dessa maneira e compartilhar sessões entre vários servidores front-end. Você pode alterar a configuração app/etc/local.xmlalternando

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

    para

    <session_save><![CDATA[db]]></session_save>
  • Use o memcached como seu armazenamento de sessão. O Magento também suporta isso por padrão. Dê uma olhada na app/etc/local.xml.additionalconfiguração. Eu nunca o usei na produção, mas ouvi dizer que isso pode ser um pouco complicado.

  • Lide com as sessões no Redis usando a brilhante extensão Cm_RedisSession de Colin Mollenhours . A configuração do Redis não deve demorar muito, também pode ser usada para armazenar em cache (consulte Cm_Cache_Backend_Redis ) e combina um cache de RAM com persistência no disco (em oposição a memcached, discos RAM ou similares), sempre no caso do servidor. falhando.

Matthias Zeis
fonte
1
Salvar as sessões no banco de dados também é mais seguro. Se o seu arquivo .htaccess não estiver lá (porque alguém excluiu a pasta var), os arquivos da sessão não estarão acessíveis do lado de fora.
Erfan 23/01
8
Salvar as sessões no banco de dados é uma má idéia. Ele não foi projetado para esse fim e o MySQL serve como uma ferramenta muito ruim para armazenamento de sessões, sendo o bloqueio um problema importante - sem mencionar nenhum suporte interno para a remoção.
Ben Lessani - Sonassi
28

Com sessões baseadas em arquivo, elas serão removidas automaticamente pelo cron de limpeza da sessão do PHP - portanto, os arquivos provavelmente serão excluídos dentro de ~ 7200 segundos após a criação. Portanto, mesmo em um site ocupado (30 mil exclusivos por dia), geralmente existem apenas cerca de 4.000 arquivos de sessão em ./var/session - o que não é nada para um servidor Linux de baixo custo.

No entanto, a limpeza na verdade depende do cron funcionando - que normalmente não aparece no diretório ./var/session do Magento. Então você deve configurar um novo cron do sistema

/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

O período de limpeza padrão para as sessões é de 7200 segundos, o que deve ser mais do que suficiente, embora você possa alterar o que foi descrito acima.

Com as sessões do Memcache, o TCP / IP é a única sobrecarga - que, para uma implantação de servidor único, o tornaria mais lento que o baseado em arquivos. Então, você usaria um soquete unix, que remove essa sobrecarga e oferece melhor segurança. Ainda assim, as sessões do cliente serão truncadas / limitadas à quantidade de RAM que você pode alocar. A sessão média do Magento é de 4Kb - portanto, você poderá suportar 256 sessões ativas, por MB alocado. Portanto, certifique-se de definir um limite apropriado para evitar que os clientes percam aleatoriamente o carrinho / sessão. E também lembre-se, uma reinicialização do daemon do Memcache apagará todas as sessões existentes (BAD!).

Com o Redis (não nativo, mas disponível por meio de uma extensão), você obtém um nível de suporte semelhante ao Memcache, mas com os benefícios adicionais da persistência (caso deseje usá-lo). Com a extensão Cm_Redis, você também poderá aproveitar a compactação de sessão. Descobrimos que essa extensão funciona muito bem nas implantações CE e EE.

Com o DB, a configuração padrão de expiração da remoção é uma poderosa semana, portanto, com o tamanho da loja acima como exemplo (30 mil exclusivos por dia), você verá um tamanho de tabela de banco de dados para core_cache_session de cerca de 7 GB - o que aumentará sua loja para uma parada completa, para quase todas as operações baseadas em sessões.

Com a experiência de hospedar lojas grandes (230k visitantes únicos por dia) e pequenas (<1k visitantes únicos por dia), nossa recomendação é:

Implantação de servidor único - arquivos

Implantação de vários servidores - Redis (usando um banco de dados separado do cache principal do Magento)

Eu escrevi algumas respostas realmente completas aqui http://magebase.com/magento-tutorials/magento-session-storage-which-to-choose-and-why/comment-page-1/#comment-1980

Ben Lessani - Sonassi
fonte
2
Se o cron de limpeza deve limpar as sessões, por que falha e como esse problema pode ser corrigido em vez de criar um novo cron que parece uma solução alternativa?
Ganso
12

Eu fiz uma pergunta relacionada há algum tempo:

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

O que eu nunca descobri (deixei esse trabalho para um novo e o problema original se tornou o de outra pessoa) é se as sessões do Magento respeitarão essas configurações ou se implementarão seu tratamento de sessões usando o Zend (e provavelmente algum tipo de zend.ini arquivo de configuração).

As configurações de php para olhar:

session.gc_maxlifetime session.gc_probability session.gc_divisor

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

pspahn
fonte
Eu adoraria saber isso sozinho, pela minha experiência, parece que o Magento não respeita essas configurações (considerando que eu tenho um total de GB de arquivos de sessão, seria seguro assumir que em algum momento o GC teria disparado). Então, acabei de configurar o script recomendado por Ben como um trabalho cron para ser seguro.
Javier Villanueva
7

Geralmente, um trabalho cron é suficiente, mas aqui estão algumas coisas a serem lembradas:

1) Defina a sessão para durar não mais que session.gc_maxlifetime( php -i | grep session.gc_maxlifetime) segundos (isso configurará sessões expiradas para serem preparadas para coleta de lixo pelo php.ini ou .htaccess)

2) Você pode querer armazenar as sessões no banco de dados, veja aqui para obter mais informações sobre como fazer isso (essa opção pode ser mais fácil de gerenciar via módulo magento personalizado)

3) Outra opção a considerar é o Memcached, que também pode acelerar os servidores (embora não esteja completamente conectado à pergunta, acho útil saber)

Consulte esta pergunta para obter mais informações: https://stackoverflow.com/questions/4353875/how-long-do-the-magento-session-files-need-to-be-kept

pzirkind
fonte
2
Usar um cronjob para simplesmente remover todos os arquivos da sessão é inaceitável. O que acontece quando um usuário adiciona itens ao carrinho 10 minutos antes da execução do cron? O carrinho deles é limpo! Se a coleta de lixo do PHP não estiver funcionando, isso precisa ser resolvido.
precisa saber é o seguinte
+1 @davidalger ponto bom, eu estava sob a suposição (equivocada) de que somente sessões expiradas estavam sendo eliminados via cronjob
pzirkind
1
@davidalger - a própria coleta de lixo do PHP opera via cron. Simplesmente finds todos os arquivos anteriores sess.gc_maxlifetimee os remove. Excluir sessões via cron é um comportamento normal, seguro e aceitável.
Ben Lessani - Sonassi
1
Na verdade, não, não é. A coleta de lixo da sessão é feita quando o início da sessão ocorre durante a execução de scripts PHP. A frequência com que a coleta de lixo é executada depende dos valores de session.gc_probabilitye session.gc_divisor. Se scripts diferentes tiverem valores diferentes para session.gc_maxlifetimeaquele com o valor mais baixo, determinará quanto tempo as coisas ficam pendentes desde que o armazenamento da sessão é global e a execução desse script limpará os outros objetos de sessões de scripts.
davidalger
5

Em todas as nossas configurações, temos um arquivo maintenance.php que cuida da limpeza do diretório logs e var de vez em quando. Como as sessões precisam ser salvas no banco de dados ou no sistema de arquivos, esse arquivo de manutenção os limpará. (Veja o código abaixo).

Você pode executar o seguinte comando como uma tarefa cron para limpar os logs:

php maintenance.php clean=log

O comando acima produzirá a seguinte saída:

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

Você pode executar o seguinte comando como uma tarefa cron para limpar a pasta var:

php maintenance.php clean=var

O comando acima produzirá a seguinte saída:

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

O código real (não se esqueça de ajustar o caminho para o seu arquivo 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
fonte
5

Para o Magento CMS e similares (que não estão limpando sessões antigas), eu apenas uso tarefas cron com base nas configurações do php.ini.

PHP5 / Ubuntu 14.04 / Debian

A configuração cron.d do sistema para php5 não limpa o Magento ./var/session (ou qualquer outra coisa além da pasta de sessão padrão (/ var / lib / php5 para Ubuntu e / var / lib / php5 / sessions ou / tmp / para a maioria dos outros Linux) dists).

Mas você ainda pode usar "sessionclean" e "maxlifetime" conforme o cron padrão do sistema php5 / Debian:

Exemplo que você pode tentar na linha de comando:

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

Portanto, apenas incorpore isso em um crontab de sistema / raiz ou em um crontab de usuário que tenha permissão de leitura / gravação para os arquivos da sessão:

$ sudo crontab -e

Adicione isto que você deseja que seja semelhante ao 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)

ou - já que sabemos que esses arquivos / diretórios existem:

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

Agora eu tenho uma quantidade gerenciável de sessões e ela é mantida limpa via coleta de lixo padrão / tempo de vida através das configurações do php.ini (cli).

(Você pode deixar o curinga acima ou substituir pelo nome do site.)

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

O script 'sessionclean' foi alterado e o script maxlifetime foi removido. Para o trabalho cron do sistema / php, agora é um script. Você realmente não pode mais usar isso, pois as chamadas de arquivo agora estão estáticas no script.

O script php5 sessionclean mais antigo ainda pode funcionar se o sistema não estiver sendo limpo. O que você pode fazer é pegar o Pacote Debian php5 mais antigo e extraí sessionclean-lo. Ou você pode simplesmente copiar isso na sua área de scripts (dando / var / www / (site) permissões / propriedade apropriadas):

#!/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

Também recomendo renomeá-lo, para que não seja confundido com o novo cronjob php 'sessionclean'. Você pode então conectar seu próprio número "maxlifetime" da seguinte maneira:

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

(61 sendo a idade do exemplo (em minutos) e 'MySessionClean' sendo o script php5 renomeado baixado ou copiado de cima).

Dessa maneira, evitamos completamente as chamadas do php.ini / env.

(EDIT 13DEC2016: LINK DE REPOUSO DE ARQUIVO DEBIANO atualizado)

bshea
fonte
3

Limpei o banco de dados regularmente de todos esses arquivos de sessão antigos. Foi um trabalho manual irritante até que eu instalei o Magento Optimizer, o que faz toda essa rotina funcionar para mim. Além disso, meu cache é atualizado constantemente e não o faço manualmente depois de alterar produtos e blocos estáticos. Ah, sim, os relatórios de erro e os carros abandonados também são limpos.

James
fonte
3

De todos os comentários acima, acho que essa é a solução fácil e espero que seja melhor que scripts longos e instalar extensões de terceiros para gerenciar arquivos de sessões antigas e manter novos arquivos de sessão.

  1. Crie um nome de arquivo "clean_session.sh" na sua magentopasta.
  2. Cole essas linhas.

#!/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. Em seguida, você pode agendar o cronjob semanalmente para executar a limpeza.

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

  1. Não se esqueça de tornar o arquivo executável como

chmod u+x clean_session.sh

  1. E você também pode executá-lo como

sh clean_session.sh

Anil
fonte
3

Para o meu caso, eu executo esse script colocado no magento/var/diretório para excluir arquivos de sessão com mais de uma semana ( -mtime +7):

#!/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

É o meu primeiro script bash (revisão 2) e acho que pode ser otimizado em vários aspectos. Estou aberto a qualquer sugestão de otimização.

Este script pode ser recuperado em: https://gist.github.com/Nolwennig/a75dc2f8628be2864bb2

Nolwennig
fonte
0

Eu criei um script que esvazia o diretório var / session. Você pode adicioná-lo a um trabalho cron para executar uma vez por dia, o que deve ser suficiente e ajustar conforme necessário. Você notará que quando o diretório da sessão for preenchido, é impossível excluir arquivos via cpanel ou ssh; esse script fará o truque apenas no diretório raiz do 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
fonte
O problema com esse script é que ele exclui todas as sessões, não apenas as antigas. Portanto, ninguém poderá fazer logon por mais de um dia (se você executar isso diariamente) e todos os carrinhos ficarão vazios após a execução (portanto, nenhum carrinho aguentará mais de um dia).
Simonthesorcerer