Назад | Перейти на главную страницу

Задача cron по сборке мусора в Ubuntu для сеансов PHP выполняется за 25 минут, почему?

В 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. Это молниеносно, но если сервер выйдет из строя или перезапустится, все ваши сеансы будут потеряны, и все будут отключены.
  • Вы также можете хранить сеансы в базе данных. Это будет немного медленнее, чем memcached, но база данных будет постоянной, и вы сможете очистить старые сеансы с помощью простого SQL-запроса. Однако, чтобы реализовать это, вы должны написать собственный обработчик сеанса.

Удаление 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 может автоматически истечь их с учетом продолжительности сеанса, установленной в коде.