Friday, 17 September 2010

ISPManager + Debian + PHP + виртуальный хостинг = мириады файлов в папке mod-tmp/bin-tmp

Не проходит и недели, чтобы вопрос о том, как победить эту напасть, хоть кто-то не задал на Серче (searchenegines.ru). Итак, вопрос - какого фига они создаются и не удаляются автоматически? Ранее, я поднимал одну из сторону этого вопроса (сколько именно должна храниться сессия) http://phpsuxx.blogspot.com/2010/04/php-debian.html, но там я упустил из виду ряд деталей.

Благодаря одному из наших клиентов (если он меня читает, передаю искреннюю благодарность) я обнаружил такой вот параметр работы PHP сессий:
session.gc_probability = 1

Этот параметр является числителем дроби, которая высчитывает вероятность запуска удаления старых файлов сессий при данном запуске PHP интерпретатора, вся дробь выглядит так:
p = session.gc_probability / session.gc_divisor

То есть, если при данном запуске PHP требуется удалять старые файлы сессий с вероятностью 1/100 (оптимальное дефалтное значение), то значения параметров должны быть 1 и 100 соответственно. Чтобы в свою очередь запретить удаление старых сессий, нужно задать session.gc_probability равным нулю.

Что же мы имеем в стандартной конфигурации свеже установленного Debian с панелью ISPManager? А вот что:

php -i | grep session.gc_
session.gc_divisor => 100 => 100
session.gc_maxlifetime => 1440 => 1440
session.gc_probability => 0 => 0

Внимание вопрос из начала поста - какого хрена? А вот такого (/etc/php5/cgi/php.ini):
; Define the probability that the 'garbage collection' process is started
; on every session initialization.
; The probability is calculated by using gc_probability/gc_divisor,
; e.g. 1/100 means there is a 1% chance that the GC process starts
; on each request.

; This is disabled in the Debian packages, due to the strict permissions
; on /var/lib/php5. Instead of setting this here, see the cronjob at
; /etc/cron.d/php5, which uses the session.gc_maxlifetime setting below.
; php scripts using their own session.save_path should make sure garbage
; collection is enabled by setting session.gc_probability
;session.gc_probability = 0
session.gc_divisor = 100

Иными словами, в связи с особенностями системы безопасности в Debian PHP gc был полностью отключен. А что за "strict permissions /var/lib/php5" ? А вот что:
su www-data
domain:~/v001049/data$ ls -la /var/lib/php5
ls: cannot open directory /var/lib/php5: Permission denied
v1:~/v001049/data$ ls -la /var/lib/php5/sess_ffae85888b2698c46af74bcbb36a534f
-rw------- 1 www-data www-data 89 2010-09-17 04:31 /var/lib/php5/sess_ffae85888b2698c46af74bcbb36a534f
domain:~/v001049/data$ cat /var/lib/php5/sess_ffae85888b2698c46af74bcbb36a534f
current_language|i:0;vote_completed|a:0:{}gids|a:1:{i:0;s:4:"1897";}counts|a:1:{i:0;i:1;}v1:~/v001049/data$
domain:~/v001049/data$
domain:~/v001049/data$ rm /var/lib/php5/sess_ffae85888b2698c46af74bcbb36a534f

То есть, в данной папке gc PHP даже теоретически работать не может - ему запретили запрос листинга каталога. Поэтому, сессии удаляются спец-скриптом /etc/cron.d/php5, который пускается от рута по CRON и проблем с правами не имеет.

Но ISPManager ведь создает отдельные папки для сессий клиентов и дает им там полную власть (листинг каталога разрешен!), следовательно, PHP gc будет там работать отлично, поэтому, опцию session.gc_probability можно смело (по крайне мере, если PHP для клиентов работает в режиме FastCGI) приводить в вид:

session.gc_probability = 1

После подобной перенастройки strace по всем PHP процессам легко показывает, что сессии мочатся:
strace -s 1024 -e trace=unlink -f $(pidof php5-cgi | sed 's/\([0-9]*\)/\-p \1/g')
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_fb03780fa60f20c40a9a3a8a653f0a48") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_a6b769c2e42878be628e9eebcff644e1") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_72db961a3a0c427dd2ca206801822eb3") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_2cd999481257e8ddf8fdc564e9b35655") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_81a55680deea55890219ad3ce0e098aa") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_1f00aa57e21437ea859d476da63e4a3c") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_735c6fbe4e76df9cb2aacc704580f934") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_1a5261a2dd852d14c1760efc7315b43d") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_c5e5cff56c2fc56f087e9bfc96c2ae0a") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_74d6c37033f2372b7187f1bffccbda78") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_456c347c477a694f9e85bfdd8cb78919") = 0
[pid 1381] unlink("/var/www/v001218/data/bin-tmp/sess_da4e80b181f5518c282f40c1de2dc3e0") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_ebe77e387b01e9de16f82aa6c35676f3") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_916646b0ed54757bd2c64a2852430af5") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_d2039dbed4dc17b7ad34b93a8820f6cf") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_7563c763ca1e997ff418d40bb945b91b") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_92f0d552abf944226e3c86e1837167b1") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_07a81fe5c04ebedfe2f48a4d55064e9b") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_23af29de2594d854b4264eee09723141") = 0
[pid 1381] unlink("/var/www/xxxxx/data/bin-tmp/sess_7856d53ddb52613410e01495a49d2381") = 0

Вот такая вот проблемка, вот такое вот решение :)

P.S. да, Миш, ты был прав, тут я накосячил поверив чужому аудиту кода PHP.

7 comments:

  1. не получается что-то..


    nihost:~# cat /etc/php5/cgi/php.ini | grep session.gc_probability
    session.gc_probability = 1

    nihost:~# /etc/init.d/apache2 restart
    ...

    nihost:~# php -i | grep gc_pro
    session.gc_probability => 0 => 0

    nihost:~#

    WTF?

    ReplyDelete
  2. У php -i конфиг хранится по пути /etc/php5/cli/php.ini, а не /etc/php5/cgi/php.ini

    ReplyDelete
  3. Ок, согласен.

    Делаем по-другому. Смотрим информацию в выводе phpinfo(). И там:

    Configuration File (php.ini) Path /etc/php5/cgi
    Loaded Configuration File /var/www/blablabla/data/php-bin/php.ini

    session.gc_divisor 100 100
    session.gc_maxlifetime 1440 1440
    session.gc_probability 0 0


    По всей видимости, при случае ispmanager, скармливать session.gc_probability = 1 надо не в общем php.ini, а в /var/www/blablabla/data/php-bin/php.ini

    ReplyDelete
  4. Не-а, лучше всего через /etc/php5/conf.d/somecompany.ini и туда именно помещать все нужные настройки. Ибо /etc/php5/cgi/php.ini перекрывается php.ini из папки юзера.

    ReplyDelete
  5. Отлично, теперь всё в порядке. Спасибо.

    ReplyDelete
  6. год 2016, а проблема та же самая :)
    спасибо за блог!

    ReplyDelete

Note: only a member of this blog may post a comment.