В Ubuntu настроено задание cron, которое ищет и удаляет старые сеансы PHP:
# Look for and purge old sessions every 30 minutes
09,39 * * * * root [ -x /usr/lib/php5/maxlifetime ] \
&& [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 \
-maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir \
fuser -s {} 2> /dev/null \; -delete
Моя проблема в том, что этот процесс занимает очень много времени с большим количеством операций ввода-вывода на диске. Вот мой график использования процессора:
Бег по уборке представлен голубыми шипами. В начале периода задания по очистке PHP были запланированы по умолчанию на 09 и 39 минут. В 15:00 я удалил 39-минутное время из cron, поэтому задание по очистке вдвое большего размера выполняется вдвое реже (вы можете видеть, что пики становятся в два раза шире и вдвое реже).
Вот соответствующие графики для времени ввода-вывода:
И дисковые операции:
На пике, когда было около 14000 активных сеансов, можно увидеть, что очистка выполняется в течение полных 25 минут, очевидно, с использованием 100% одного ядра ЦП и того, что кажется 100% дискового ввода-вывода за весь период. Почему это так ресурсоемко? An ls
каталога сеансов /var/lib/php5
занимает всего долю секунды. Так почему же на обрезку старых сессий уходит целых 25 минут? Что я могу сделать, чтобы это ускорить?
Файловая система для этого устройства в настоящее время - ext4, работающая на 64-битной Ubuntu Precise 12.04.
РЕДАКТИРОВАТЬ: Я подозреваю, что загрузка происходит из-за необычного процесса «фьюзер» (поскольку я ожидаю простой rm
быть чертовски быстрее, чем производительность, которую я вижу). Я собираюсь отказаться от фьюзера и посмотреть, что произойдет.
Поздравляем с тем, что у вас есть популярный веб-сайт и вы можете поддерживать его работу на виртуальной машине все это время.
Если вы действительно получаете два миллиона просмотров страниц в день, тогда вы собираетесь накопить МНОГО сеансов PHP в файловой системе, и их удаление займет много времени, независимо от того, используете ли вы fuser
или rm
или пылесос.
На этом этапе я бы порекомендовал вам изучить альтернативные способы хранения ваших сессий:
memcached
. Это молниеносно, но если сервер выйдет из строя или перезапустится, все ваши сеансы будут потеряны, и все будут отключены.Удаление fuser
должно помочь. Эта работа выполняется fuser
команда (проверьте, открыт ли файл в данный момент) для каждого найденного файла сеанса, что может легко занять несколько минут в загруженной системе с 14k сеансами. это была ошибка Debian (Ubuntu основан на Debian).
Вместо memcached вы также можете попробовать использовать tmpfs (файловую систему в памяти) для файлов сеанса. Как и memcached, это приведет к недействительности сеансов при перезагрузке (это можно обойти, создав резервную копию этого каталога где-нибудь в сценарии выключения и восстановив в сценарии запуска), но будет намного проще настроить. Но это не поможет fuser
проблема.
Итак, варианты хранения сеансов Memcached и базы данных, предложенные здесь пользователями, являются хорошим выбором для повышения производительности, каждый со своими преимуществами и недостатками.
Но при тестировании производительности я обнаружил, что огромная стоимость обслуживания этого сеанса почти полностью сводится к вызову fuser
в работе cron. Вот графики производительности после возврата к заданию cron Natty / Oneiric, которое использует rm
вместо того fuser
чтобы обрезать старые сеансы, переключение происходит в 2:30.
Как видите, периодическое снижение производительности, вызванное очисткой PHP-сеанса Ubuntu, почти полностью устранено. Пики, показанные на графике «Операции с дисками», теперь намного меньше по величине и настолько тонкие, насколько это возможно на этом графике, показывая небольшое короткое нарушение, когда ранее производительность сервера значительно снижалась в течение 25 минут. Полностью устранено дополнительное использование ЦП, теперь это задание, связанное с вводом-выводом.
(несвязанное задание ввода-вывода выполняется в 05:00, а задание ЦП - в 7:40, что вызывает собственные всплески на этих графиках)
Модифицированное задание cron, которое я сейчас выполняю:
09 * * * * root [ -x /usr/lib/php5/maxlifetime ] && \
[ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 \
-maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -print0 \
| xargs -n 200 -r -0 rm
Я наткнулся на этот пост, когда проводил некоторое исследование сессий. Хотя принятый ответ очень хорош (и вызов fuser был удален из сценария gc на некоторое время), я думаю, что стоит отметить несколько других соображений, если кто-то еще столкнется с аналогичной проблемой.
В описанном сценарии OP использовал ext4. Каталоги в ext4 хранят данные файлов в формате базы данных htree - это означает, что хранение большого количества файлов в одном каталоге незначительно по сравнению с их распределением по нескольким каталогам. Это верно не для всех файловых систем. Обработчик по умолчанию в PHP позволяет вам использовать несколько подкаталогов для файлов сеанса (но обратите внимание, что вы должны проверить, что процесс управления повторяется в этих каталогах - в приведенном выше задании cron этого не происходит).
Большая часть затрат на операцию (после удаления вызова фьюзера) возникает из-за просмотра файлов, которые еще не устарели. Использование (например) одного уровня подкаталогов и 16 заданий cron, просматривающих каждый подкаталог (0 /, 1 /, ... d /, e /, f /), сгладит возникающие удары нагрузки.
Использование настраиваемого обработчика сеанса с более быстрой подложкой поможет - но есть из чего выбрать (memcache, redis, сокет обработчика mysql ...), оставляя в стороне диапазон качества тех, которые опубликованы в Интернете, который вы выбираете, зависит от точного требования в отношении вашего приложения, инфраструктуры и навыков, не забывая, что часто существуют различия в обработке семантики (особенно блокировки) по сравнению с обработчиком по умолчанию.
С таким трафиком не следует ставить сеансы на тормозах. Вы должны использовать что-то вроде memcache. Все, что вам нужно сделать, это настроить php, и менять код не нужно. См. Например
http://www.dotdeb.org/2008/08/25/storing-your-php-sessions-using-memcached/
Причина, по которой это занимает так много времени, связана с огромным количеством файлов, которые необходимо отсортировать, чтобы увидеть, какие из них можно удалить. Memcache может автоматически истечь их с учетом продолжительности сеанса, установленной в коде.