我该如何处理过多的会话文件?


43

我是几个拥有Magento站点的服务器的系统管理员,有时它们会填充会话文件。

有人告诉我,在Magento中无法管理这些文件,我认为它们的临时使用意味着不能将其关闭,但Magento无法处理这些文件的删除似乎很奇怪文件?

我的解决方案是每晚执行一次crontab,执行类似这样的操作,find /path/to/magento/sessions/ -name "sess*" -type f -delete但至少可以说这不太礼貌。

处理这些的最佳方法是什么?

Answers:


37

除了find使用其他人提到的使用自定义修改时间删除会话文件之外,您还可以:

  • 将会话保存在数据库中。当然,这会给数据库带来负担,但这不是最快的方法,但是您可以通过这种方式处理更多的会话,并且可以在多个前端服务器之间共享会话。您可以app/etc/local.xml通过切换来更改设置

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

    <session_save><![CDATA[db]]></session_save>
  • 使用memcached作为会话存储。Magento默认情况下也支持此功能。看一下app/etc/local.xml.additional配置。我从未在生产中使用过它,但听说这可能有些棘手。

  • 使用Colin Mollenhours出色的扩展Cm_RedisSession处理Redis中会话。设置Redis不会花费太长时间,也可以用于缓存(请参阅Cm_Cache_Backend_Redis),并将RAM缓存与持久性结合在磁盘上(与memcached,RAM磁盘等类似),以防万一您的服务器崩溃。


1
将会话保存在数据库中也更加安全。如果您的.htaccess文件不存在(因为有人删除了var文件夹),则无法从外部访问您的会话文件。
Erfan 2013年

8
将会话保存在数据库中是一个坏主意。它不是为此目的而设计的,MySQL用作会话存储的工具非常差,锁定是关键问题-更不用说没有内置的清除支持。
Ben Lessani-Sonassi

28

对于基于文件的会话,它们将由PHP会话清理cron自动修剪-因此文件很可能在创建后的约7200秒内被删除。因此,即使在繁忙的站点(每天3万个唯一身份)上,。/ var / session中通常也只有大约4,000个会话文件-即使对于低端Linux服务器也没有任何作用。

但是,清理实际上取决于cron的工作-通常不在Magento的./var/session目录中查找。所以你应该建立一个新的系统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

会话的默认清理时间是7200秒,这应该足够了,尽管您可以根据需要进行更改。

对于Memcache会话,TCP / IP是唯一的开销–对于单服务器部署,这将使其速度比基于文件的速度慢。因此,您将改为使用unix套接字,这样可以减少开销并提供更好的安全性。但是,即使如此,您的客户会话也会因可分配的RAM数量而被截断/限制。Magento的平均会话为4Kb –因此,您可以为分配的每个MB支持256个活动会话。因此,请务必设置适当的限制,以避免客户随机丢失购物车/会话。还要记住,Memcache守护程序重新启动将清除所有现有会话(BAD!)。

使用Redis(不是本机的,但可以通过扩展使用),您将获得与Memcache相似的支持级别,但是具有持久性的额外好处(您应该使用它)。使用Cm_Redis扩展,您还可以利用会话压缩。我们发现此扩展在CE和EE部署上都能很好地工作。

与DB一起使用时,默认修剪期限设置可能是1周,因此,以上述存储大小为例(每天3万个唯一身份),您将看到core_cache_session的DB表大小约为7GB –这将使您的数据库工作量变大几乎所有基于会话的操作都将您的商店彻底停工。

从托管大型(每天23万唯一身份访问者)和小型(每天<1k唯一身份访问者)商店的经验来看,我们的建议是:

单服务器部署-文件

多服务器部署-Redis(使用与Magento主缓存独立的数据库)

我在这里http://magebase.com/magento-tutorials/magento-session-storage-which-to-choose-and-why/comment-page-1/#comment-1980上写了一些非常详尽的回复


2
如果清理cron应该清除会话,为什么会失败,以及如何解决这个问题而不是创建感觉像是在解决问题的新cron?

12

我前段时间已经问过一个相关的问题:

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

我从来没有发现(我离开了那份工作,原来的问题变成了其他人的工作)是Magento的会话是否会接受这些设置,或者是否使用Zend(可能是某种zend.ini)实现了会话处理。配置文件)。

要查看的php设置:

session.gc_maxlifetime session.gc_probability session.gc_divisor

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


我很想知道这一点,根据我的经验,Magento似乎不接受这些设置(考虑到我已经理解了GB的会话文件的价值,可以肯定地认为GC会在某个时候触发)。因此,为了安全起见,我只是将Ben建议的脚本设置为cron作业。
哈维尔·比亚努耶娃

7

通常,执行cron作业就足够了,但是请记住以下几点:

1)将会话设置为不超过session.gc_maxlifetimephp -i | grep session.gc_maxlifetime)秒(这将设置过期的会话,以供php.ini或.htaccess进行垃圾回收)

2)您可能希望将会话存储在数据库中,有关如何执行此操作的更多信息,请参见此处(通过自定义magento模块可能更易于管理此选项)

3)要考虑的另一种选择是Memcached巫婆还可以加快服务器速度(尽管没有完全连接到问题,我认为了解这一点很有用)

有关更多信息,请参见此问题:https : //stackoverflow.com/questions/4353875/how-long-do-the-magento-session-files-need-to-be-keep


2
使用cronjob简单地删除所有会话文件是不可接受的。当用户在cron运行前10分钟将商品添加到购物车中时,会发生什么情况?他们的手推车擦干净了!如果PHP的垃圾回收不起作用,则需要弄清楚。
davidalger

+1 @davidalger好点,我是在(错误的)假设下通过cronjob删除仅过期的会话
pzirkind

1
@davidalger-PHP自己的垃圾收集通过cron运行。它只是将find所有文件早于sess.gc_maxlifetime并删除它们。通过cron删除会话是正常,安全且可接受的行为。
Ben Lessani-Sonassi

1
其实不,不是。在PHP脚本执行期间发生会话启动时,将完成会话垃圾回收。如何频繁的垃圾收集运行依赖的价值观session.gc_probabilitysession.gc_divisor。如果不同的脚本对于session.gc_maxlifetime具有最低值的脚本具有不同的值,则由于会话存储是全局的,因此该值将确定东西闲逛多长时间,并且该脚本的执行将清除其他脚本会话对象。
davidalger

5

在我们所有的设置中,我们都有一个maintenance.php文件,该文件会不时清理日志和var目录。由于必须将会话保存在数据库或文件系统中,因此此维护文件将清除它们。(请参见下面的代码)。

您可以将以下命令作为cron作业来清理日志:

php maintenance.php clean=log

上面的命令将产生以下输出:

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

您可以将以下命令作为cron作业来清理var文件夹:

php maintenance.php clean=var

上面的命令将产生以下输出:

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

实际的代码(别忘了调整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;
    }
}

5

对于Magento CMS等(它们不会清除旧的会话),我只使用基于php.ini设置的cron作业。

PHP5 / Ubuntu 14.04 / Debian

php5的系统cron.d设置无法清除Magento ./var/session(或默认会话文件夹以外的任何内容(对于Ubuntu和/ var / lib / php5 / sessions或对于大多数其他Linux的/ tmp /除外) dists)。

但是您仍然可以按照默认的php5 / Debian系统cron使用“ sessionclean”和“ maxlifetime”:

您可以从命令行尝试的示例:

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

因此,只需将其合并到具有会话文件读写权限的系统/根crontab或用户的crontab中:

$ sudo crontab -e

添加这个就是您希望它看起来类似于系统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)

或-因为我们知道这些文件/目录存在:

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

现在,我拥有可管理的会话数量,并且通过php.ini(cli)设置通过默认垃圾收集/生命周期保持干净。

(您可以将通配符保留在上面,也可以将其替换为站点名称。)

编辑(PHP7 / Ubuntu 16.xx / Debian):

'sessionclean'脚本已更改,maxlifetime脚本已删除。对于system / php cron作业,现在是一个脚本。您现在不能再真正使用它了,因为文件调用现在对于脚本是静态的。

如果系统无法清理,较旧的php5 sessionclean脚本仍然可以为您工作。您可以做的是获取旧的Debian php5软件包并从中提取sessionclean。或者,您可以简单地将其复制到您的脚本区域(给予适当的/ var / www /(site)权限/所有权):

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

我还建议重命名它,因此不要与新的php'sessionclean'cronjob混淆。然后,您可以像这样插入自己的“ maxlifetime”号码:

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

(61是示例年龄(以分钟为单位),“ MySessionClean”是从上面下载或复制的重命名的php5脚本)。

通过这种方式,我们完全避免了php.ini / env调用。

(编辑13DEC2016:更新的DEBIAN档案回购链接)


3

我从所有这些旧的会话文件中定期清除了数据库。直到我安装了Magento Optimizer,这使所有这些例行工作对我来说都很麻烦。另外,我的缓存会不断刷新,更改产品和静态块后不会手动刷新。哦,是的,错误报告和废弃的购物车也要清理。


3

在以上所有评论中,我认为这是简单的解决方案,希望它比长脚本更好,并希望安装第三方扩展来管理旧的会话文件并保留新的会话文件。

  1. 在您的magento文件夹下创建一个文件名称“ clean_session.sh” 。
  2. 粘贴这些行。

#!/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. 然后,您可以每周安排cronjob进行清理。

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

  1. 不要忘记使文件可执行为

chmod u+x clean_session.sh

  1. 您也可以将其运行为

sh clean_session.sh


3

就我而言,我运行了放置在magento/var/目录中的此脚本,用于删除会话文件,时间超过一周(-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

这是我的第一个bash脚本(修订版2),我认为可以在多个方面进行优化。我愿意接受任何优化建议。

可以在以下位置获取此脚本:https : //gist.github.com/Nolwennig/a75dc2f8628be2864bb2


0

我创建了一个清空var / session目录的脚本。您可以将其添加到cron作业中,以每天运行一次,这应该足够了,并可以根据需要进行调整。您会注意到当会话目录被填满时,无法通过cpanel或ssh删除文件,此脚本将完成仅放置在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);

该脚本的问题在于它会删除所有会话,而不仅仅是旧会话。因此,没有人可以登录超过一天的时间(如果每天运行),并且所有购物车在运行后都将为空(因此,任何购物车都不能保存超过一天的时间)。
simonthesorcerer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.