Jak obsługiwać pliki sesji, które stają się zbyt liczne?

43

Działam jako sysadmin dla kilku serwerów, które przechowują strony Magento i czasami wypełniają się plikami sesji.

Powiedziano mi, że zarządzanie tymi plikami nie jest czymś, co można zrobić z poziomu Magento, i przypuszczam, że ich tymczasowe użycie oznacza, że ​​nie można ich po prostu wyłączyć, ale wydaje się dziwne, że Magento nie ma sposobu na usunięcie tych plików akta?

Moje rozwiązanie to nocny crontab, który wykonuje coś takiego, find /path/to/magento/sessions/ -name "sess*" -type f -deleteale co najmniej nie wydaje się być grzeczny.

Jak najlepiej sobie z tym poradzić?

Toby
źródło

Odpowiedzi:

37

Oprócz usuwania plików sesji przy findużyciu niestandardowego czasu modyfikacji, o którym wspominają inni, możesz także:

  • Zapisz sesje w swojej bazie danych . Oczywiście spowoduje to obciążenie bazy danych i nie jest to najszybszy sposób, ale w ten sposób możesz obsłużyć o wiele więcej sesji i możesz udostępniać sesje wielu serwerom frontendowym. Możesz zmienić ustawienie app/etc/local.xml, przełączając

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

    do

    <session_save><![CDATA[db]]></session_save>
  • Użyj memcached jako magazynu sesji. Magento również obsługuje to domyślnie. Sprawdź app/etc/local.xml.additionalkonfigurację. Nigdy nie używałem go w produkcji, ale słyszałem, że może to być trochę trudne.

  • Obsługiwać sesje w Redis pomocą Colin Mollenhours genialne rozszerzenie Cm_RedisSession . Konfiguracja Redis nie powinna zająć zbyt długo, może być również używana do buforowania (patrz Cm_Cache_Backend_Redis ) i łączy pamięć podręczną RAM z trwałością na dysku (w przeciwieństwie do memcached, dysków RAM itp.), Co zawsze ma miejsce w przypadku, gdy serwer jest upaść.

Matthias Zeis
źródło
1
Zapisywanie sesji w bazie danych jest również bezpieczniejsze. Jeśli pliku .htaccess nie ma (ponieważ ktoś usunął folder var), pliki sesji nie będą dostępne z zewnątrz.
Erfan
8
Zapisywanie sesji w bazie danych to zły pomysł. Nie jest on przeznaczony do tego celu, a MySQL służy jako bardzo słabe narzędzie do przechowywania sesji, blokowanie jest kluczową kwestią - nie wspominając o żadnej wbudowanej obsłudze czyszczenia.
Ben Lessani - Sonassi
28

W przypadku sesji opartych na plikach będą one automatycznie przycinane przez crona do czyszczenia sesji PHP - więc pliki prawdopodobnie zostaną usunięte w ciągu ~ 7200 sekund od utworzenia. Tak więc nawet na ruchliwej stronie (30 000 unikalnych użytkowników dziennie) w ./var/session zwykle znajduje się tylko około 4000 plików sesji - co nie jest niczym nawet dla niskiej klasy serwera Linux.

Jednak czyszczenie w rzeczywistości zależy od działania crona - który zwykle nie szuka w katalogu ./var/session Magento. Powinieneś więc skonfigurować nowy systemowy 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

Domyślny okres czyszczenia dla sesji wynosi 7200 sekund, co powinno być więcej niż wystarczające, chociaż można zmienić powyższe w celu dopasowania.

W przypadku sesji Memcache TCP / IP to jedyny narzut - który w przypadku wdrożenia na jednym serwerze sprawiłby, że byłby wolniejszy niż oparty na plikach. Zatem użyłbyś zamiast tego gniazda unixowego, które usuwa to obciążenie i daje większe bezpieczeństwo. Ale nawet sesje klienta zostaną obcięte / ograniczone pod względem ilości pamięci RAM, którą można przydzielić. Średnia sesja Magento to 4Kb - więc będziesz w stanie obsłużyć 256 aktywnych sesji na przydzielony MB. Należy więc ustawić odpowiedni limit, aby uniknąć przypadkowej utraty koszyka / sesji przez klientów. Pamiętaj też, że ponowne uruchomienie demona Memcache usunie wszystkie istniejące sesje (BAD!).

Dzięki Redis (nie natywnemu, ale dostępnemu przez rozszerzenie) otrzymujesz podobny poziom wsparcia jak Memcache, ale z dodatkowymi zaletami trwałości (jeśli chcesz go użyć). Dzięki rozszerzeniu Cm_Redis będziesz mógł również skorzystać z kompresji sesji. Odkryliśmy, że to rozszerzenie działa bardzo dobrze zarówno we wdrożeniach CE, jak i EE.

Przy DB, domyślne ustawienie ważności suszonych śliwek to potężny 1 tydzień, więc biorąc pod uwagę powyższy rozmiar sklepu jako przykład (30 tys. Unikatów dziennie), będziesz patrzył na rozmiar tabeli DB dla core_cache_session około 7 GB - co będzie szlifować Twój sklep całkowicie się zatrzyma, na prawie każdą operację opartą na sesji.

Z doświadczenia hostingu zarówno dużych (230 tys. Unikalnych odwiedzających dziennie), jak i małych (<1 tys. Unikalnych odwiedzających dziennie), zalecamy:

Wdrożenie na jednym serwerze - pliki

Wdrożenie na wielu serwerach - Redis (przy użyciu oddzielnej bazy danych od głównej pamięci podręcznej Magento)

Napisałem kilka naprawdę dokładnych odpowiedzi tutaj http://magebase.com/magento-tutorials/magento-session-storage-which-to-choose-and-why/comment-page-1/#comment-1980

Ben Lessani - Sonassi
źródło
2
Jeśli oczyszczający cron ma za zadanie wyczyścić sesje, dlaczego się nie udaje i jak można rozwiązać ten problem zamiast tworzyć nowy cron, który wydaje się być obejściem?
Goose
12

Jakiś czas temu zadałem powiązane pytanie:

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

To, czego nigdy się nie dowiedziałem (zostawiłem tę pracę na nową, a pierwotny problem stał się czyjąś inną), dotyczy tego, czy sesje Magento będą honorować te ustawienia, czy też zaimplementują obsługę sesji za pomocą Zend (i prawdopodobnie jakiegoś rodzaju zend.ini plik konfiguracyjny).

Ustawienia php do obejrzenia:

session.gc_maxlifetime session.gc_probability session.gc_divisor

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

pspahn
źródło
Chciałbym to wiedzieć sam, z mojego doświadczenia wynika, że ​​Magento nie szanuje tych ustawień (biorąc pod uwagę, że mam pliki sesji o wartości gottent GB, można bezpiecznie założyć, że w pewnym momencie GC by się uruchomił). Właśnie dlatego ustawiłem zalecany skrypt Bena jako zadanie crona, aby było bezpieczne.
Javier Villanueva
7

Zwykle wystarcza praca crona, ale oto kilka rzeczy, o których należy pamiętać:

1) Ustaw sesję tak, aby nie trwała dłużej niż session.gc_maxlifetime( php -i | grep session.gc_maxlifetime) sekundy (spowoduje to skonfigurowanie wygasłych sesji, które będą przygotowane do odśmiecania przez php.ini lub .htaccess)

2) Możesz zapisać sesje w bazie danych , aby uzyskać więcej informacji o tym, jak to zrobić (ta opcja może być łatwiejsza do zarządzania za pomocą niestandardowego modułu magento)

3) Inną opcją do rozważenia jest to, że Memcached, która może również przyspieszyć serwery (choć nie jest całkowicie związana z pytaniem, myślę, że warto o tym wiedzieć)

Zobacz to pytanie, aby uzyskać więcej informacji: https://stackoverflow.com/questions/4353875/how-long-do-the-magento-session-files-need-to-be-kept

pzirkind
źródło
2
Niedopuszczalne jest używanie cronjob do prostego usuwania wszystkich plików sesji. Co się stanie, gdy użytkownik doda rzeczy do koszyka na 10 minut przed uruchomieniem crona? Ich wózek jest czyszczony! Jeśli zbieranie śmieci przez PHP nie działa, należy to rozgryźć.
davidalger
+1 @davidalger dobry punkt, byłem przy (błędnym) założeniu, że tylko wygasłe sesje były usuwane przez cronjob
pzirkind
1
@davidalger - własne śmieciowanie PHP działa za pośrednictwem crona. Po prostu finds wszystkie pliki starsze niż sess.gc_maxlifetimei usuwa. Usuwanie sesji za pomocą crona to normalne, bezpieczne i dopuszczalne zachowanie.
Ben Lessani - Sonassi
1
Właściwie nie, nie jest. Odśmiecanie sesji jest wykonywane, gdy sesja rozpoczyna się podczas wykonywania skryptów PHP. Częstotliwość uruchamiania odśmiecania zależy od wartości session.gc_probabilityi session.gc_divisor. Jeśli różne skrypty mają różne wartości dla session.gc_maxlifetimetej o najniższej wartości, określi, jak długo rzeczy się zawieszają, ponieważ pamięć sesji jest globalna, a wykonanie tego skryptu wyczyści obiekty sesji innych skryptów.
dawidger
5

We wszystkich naszych konfiguracjach mamy plik Maintenance.php, który od czasu do czasu zajmuje się czyszczeniem logów i katalogu var. Ponieważ sesje muszą być zapisane w bazie danych lub w systemie plików, ten plik konserwacji wyczyści je oba. (Zobacz kod poniżej).

Aby wyczyścić dzienniki, możesz uruchomić następujące polecenie jako zadanie cron:

php maintenance.php clean=log

Powyższe polecenie wygeneruje następujące dane wyjściowe:

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

Aby wyczyścić folder var, możesz uruchomić następujące polecenie jako zadanie cron:

php maintenance.php clean=var

Powyższe polecenie wygeneruje następujące dane wyjściowe:

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

Rzeczywisty kod (nie zapomnij dostosować ścieżki do pliku 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
źródło
5

W przypadku Magento CMS i tym podobnych (które nie usuwają starych sesji), po prostu używam zadań cron opartych na ustawieniach php.ini.

PHP5 / Ubuntu 14.04 / Debian

Systemowa konfiguracja cron.d dla php5 nie czyści Magento ./var/session (ani niczego poza domyślnym folderem sesji (/ var / lib / php5 dla Ubuntu i / var / lib / php5 / session lub / tmp / dla większości innych Linuksa) dists).

Ale nadal możesz używać „sessionclean” i „maxlifetime” zgodnie z domyślnym cronem systemu php5 / Debian:

Przykład, który możesz wypróbować z wiersza poleceń:

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

Więc po prostu włącz to do crontab systemu / root lub crontab użytkownika, który ma uprawnienia do odczytu / zapisu plików sesji:

$ sudo crontab -e

Dodaj, jeśli chcesz, aby wyglądał podobnie do systemowego php crona:

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)

lub - skoro wiemy, że te pliki / katalogi istnieją:

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

Teraz mam możliwą do zarządzania liczbę sesji i jest utrzymywana w czystości przez domyślne śmieciowanie / czas życia poprzez ustawienia php.ini (cli).

(Możesz zostawić symbol wieloznaczny powyżej lub zastąpić nazwą witryny.)

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

Skrypt „sessionclean” zmienił się, a skrypt maksymalny okres użytkowania został usunięty. Dla zadania system / php cron jest to teraz jeden skrypt. Naprawdę nie możesz już tego używać, ponieważ wywołania plików są teraz statyczne dla skryptu.

Starszy skrypt php5 sessionclean może nadal działać, jeśli system się nie czyści. Co możesz zrobić, to pobrać starszy pakiet php5 Debiana i wypakować sessioncleango. Możesz też po prostu skopiować to do obszaru skryptów (podając odpowiednie uprawnienia / własność / var / www / (strona)):

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

Polecam także zmienić jego nazwę, aby nie mylić go z nowym cronjobem php 'sessionclean'. Następnie możesz podłączyć swój własny „maksymalny okres użytkowania” w następujący sposób:

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

(61 to wiek przykładowy (w minutach), a „MySessionClean” to zmieniony skrypt php5 pobrany lub skopiowany z góry).

W ten sposób unikamy wywołań php.ini / env.

(EDYCJA 13DEC2016: Zaktualizowano DEBIAN ARCHIWUM REPO LINK)

bshea
źródło
3

Wyczyściłem DB regularnie ze wszystkich tych starych plików sesji. Do czasu zainstalowania Magento Optimizer była to irytująca praca ręczna, która sprawia, że ​​cała ta rutyna działa dla mnie. Ponadto moja pamięć podręczna jest stale odświeżana i nie zmieniam jej ręcznie po zmianie produktów i bloków statycznych. Och, tak, raporty błędów i porzucone wózki również są czyszczone.

James
źródło
3

Ze wszystkich powyższych komentarzy uważam, że jest to łatwe rozwiązanie i mam nadzieję, że będzie ono lepsze niż długie skrypty i instalowanie rozszerzenia innej firmy w celu zarządzania starymi plikami sesji i zachowania nowych plików sesji.

  1. Utwórz nazwę pliku „clean_session.sh” w swoim magentofolderze.
  2. Wklej te linie.

#!/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. Następnie możesz zaplanować cronjob co tydzień, aby wykonać czyszczenie.

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

  1. Nie zapomnij, aby plik był wykonywalny jako

chmod u+x clean_session.sh

  1. Możesz także uruchomić jako

sh clean_session.sh

Indygowiec
źródło
3

W moim przypadku uruchamiam ten skrypt umieszczony w magento/var/katalogu, aby usunąć pliki sesji -mtime +7starsze niż tydzień ( ):

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

To mój pierwszy skrypt bash (wersja 2) i myślę, że można go zoptymalizować pod wieloma względami. Jestem otwarty na wszelkie sugestie dotyczące optymalizacji.

Ten skrypt można pobrać ze strony: https://gist.github.com/Nolwennig/a75dc2f8628be2864bb2

Nolwennig
źródło
0

Stworzyłem skrypt, który opróżnia katalog var / session. Możesz dodać go do zadania crona, aby uruchamiało się raz dziennie, co powinno wystarczyć i odpowiednio dostosowywać. Zauważysz, kiedy katalog sesji zostanie zapełniony, nie da się usunąć plików przez cpanel lub ssh, ten skrypt zrobi lewy w katalogu głównym 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
źródło
Problem z tym skryptem polega na tym, że usuwa on wszystkie sesje, nie tylko te stare. Dlatego nikt nie może być zalogowany dłużej niż jeden dzień (jeśli uruchamiasz to codziennie), a wszystkie wózki będą puste po tym czasie (więc żaden wózek nie będzie trwał dłużej niż jeden dzień).
simonthesorcerer