Php session gc probability

Как устроены сессии в PHP, как реализован данный механизм в MODX Revolution и как его можно улучшить

Работая над оптимизацией сайта проекта Лектория, я всегда ищу узкие места, которые в перспективе могут привести к существенным проблемам и стараюсь их в максимально короткие сроки закрывать. Одним из таких вопросов, с которыми я недавно столкнулся, оказался вопрос работы стандартного механизма обработки сессий в MODX.

Автор материала

Артем Зернов . Веб-разработчик, создатель проекта Лектория, эксперт MODX Revolution, директор веб-студии OpenColour. Youtube-канал OpenModx.

Как я начал ковыряться в этом вопросе

Меня зовут Артем Зернов. Я веб-разработчик, занимаюсь развитием проекта Лектория, а также веду свой youtube-канал OpenModx, а еще у меня есть веб-студия OpenColour, в которой мы создаем сайты, в основном на MODX Revolution. В процессе своей деятельности в нашей команде мы создали не одну сотню сайтов, и в процессе их обслуживания я замечал, что некоторые, наиболее посещаемые сайты начинали тормозить. Причиной тому была таблица modx_session, о которой мы поговорим позже. Столкнувшись с этой проблемой, я начал разбираться, как устроен механизм сессий в PHP и MODX в частности. И вот буквально сегодня я вновь вернулся к этому вопросу, анализируя поведение сайта Лектории. Спешу поделиться своими наблюдениями и идеями.

Как устроены сессии в PHP по-умолчанию

При посещении какой-либо веб-страницы сайта, созданного на PHP, создается сессия. При этом, если у вас в cookie нет параметра с идентификатором сессии (по-умолчанию это PHPSESSID), то сервер устанавливает вам куки и теперь сервер знает, какая сессия должна быть ассоциирована с вашим визитом.

В сессии хранятся данные, которые присущи только вашему визиту. Например, корзина товаров, информация о том, авторизовались ли вы для входа в личный кабинет и так далее.

Пока у вас есть в куки идентификатор сессии, сервер знает, кто вы и может показывать вам какие-либо ваши данные, хранимые в сессии.

Читайте также:  Сумма чисел Фибоначчи из иходного массива

По-умолчанию, в php есть встроенные функции session_start, session_write_close и прочие функции с префиксом session_. Полный набор функций можно посмотреть по ссылке:

Также есть глобальный массив $_SESSION, в который вы можете записывать что угодно. MODX также записывает в него свои служебные данные.

Пока сессия открыта и пока не вызван метод session_write_close, все манипуляции с данными в $_SESSION будут сохраняться при переходах между страницами в рамках вашего посещения.

По-умолчанию, в php сессии хранятся в файлах, хранимых во временном каталоге (например /tmp). Также в дистрибутиве php содержится bash-скрипт sessionclean, который автоматически устанавливается в системные таймеры (можно сказать — это cron) и с периодичностью раз в 30 минут очищает устаревшие сессии, чтобы они не занимали лишнее пространство на диске.

Сессии устаревают по принципу » Если с момента последнего обращения к сессии прошло больше времени, чем укзано в настройке php session.gc_maxlifetime, то считаем ее устаревшей «.

Сессии — это временные хранилища, связанные с конкретным посетителем, а точнее с браузером. В сессии хранятся данные, потеря которых не несет существенных последствий.

Как и где инициализируются обработчики сессии в MODX

Прежде, чем сказать о том, как это происходит в MODX, важно сказать, что php предусматривает переопределение стандартных механизмов работы с сессиями. Это делается при помощи встроенной в php функции session_set_save_handler, с помощью которой мы можем переопределить способ чтения, записи и очистки от устаревших сессий (сборки мусора).

Источник

session_gc

session_gc() используется для выполнения сборки мусора (garbage collection) для данных сессии. По умолчанию PHP выполняет основанную на вероятности сборку мусора сессии.

Сборка мусора, основанная на вероятности в целом работает, но имеет несколько проблем. 1) На низкозагруженных сайтах данные сессии могут быть не удалены в течение желаемого времени. 2) На высокозагруженных сайтах сборка мусора может выполняться слишком часто. 3) Сборка мусора выполняется во время обработки запроса пользователя, что приводит к дополнительной задержке для пользователя.

Поэтому рекомендуется выполнять сборку мусора на рабочих системах периодически, например, использовать задачи cron в UNIX-подобных системах. При этом убедитесь, что отключили сборку мусора на основе вероятности, установив session.gc_probability в 0.

Список параметров

У этой функции нет параметров.

Возвращаемые значения

session_gc() возвращает число удалённых данных сессии при успешном выполнении и false в случае неудачи.

Старые обработчики сессии не возвращают число удалённых данных сессии, а только флаг успеха/неудачи. В этом случае, число удалённых данных сессии всегда будет равно 1, независимо от фактического количества удалённых данных.

Читайте также:  Php fpm script error

Примеры

Пример #1 Пример использования session_gc() в диспетчерах задач, таких как cron

// Примечание: Данный скрипт должен выполняться под тем же пользователем процесса веб-сервера.

// Нужна активная сессия для инициализации доступа к хранилищу данных сессии.
session_start ();

// Принудительное выполнение сборки мусора
session_gc ();

// Очистка идентификатора сессии
session_destroy ();
?>

Пример #2 Пример использования session_gc() в скрипте, доступном пользователю

// Примечание: session_gc() рекомендуется использовать через скрипт диспетчера задач,
// но можно использовать и следующим образом.

// Используется для проверки времени последней сборки мусора
$gc_time = ‘/tmp/php_session_last_gc’ ;
$gc_period = 1800 ;

session_start ();
// Выполнять сборку мусора только по истечении периода,
// поскольку вызов session_gc() при каждом запросе является пустой тратой ресурсов.
if ( file_exists ( $gc_time )) if ( filemtime ( $gc_time ) < time () - $gc_period ) session_gc ();
touch ( $gc_time );
>
> else touch ( $gc_time );
>
?>

Смотрите также

  • session_start() — Стартует новую сессию, либо возобновляет существующую
  • session_destroy() — Уничтожает все данные сессии
  • session.gc_probability

Источник

Неожиданное поведение Garbage Collector’а сессий

На днях я столкнулся с очень интересной проблемой. В системе, с которой я разбирался, использовался механизм ограничения времени жизни сессии. Валидация этого времени перекладывалась на плечи garbage collector’а, который почему-то её выполнял не совсем добросовестно, а то и вовсе не выполнял. Как оказалось, ошибки эти общераспространенных, по этому о тонкостях работы с GC я и хотел бы рассказать.

В php за работу GC для сессий отвечают 3 параметра: session.gc_probability, session.gc_divisor и session.gc_maxlifetime.
Эти параметры говорят о следующем: в gc_probability из gc_divisor запусков session_start запускается GC, который должен очистить сессии со временем последнего обращения больше, чем gc_maxlifetime.

Делаем как все, или пример №1

Обновим этот файл 10 раз с промежутком секунд по 10-15(можно и больше, важно чтобы промежуток был выше чем 1 секунда). В результате мы получим «неожиданные ответы»:

Причина довольно проста и, я бы сказал, очевидна:
gc запустится только в 1 из 1000 запросов, а мы сделали всего 15.

Примечание: большинство из систем, которые я видел, работали по этому алгоритму и глубже не заходили.

Обойти баг любой ценой, или пример №2

Но поведение этого скрипта становится намного более неожиданным. Давайте попробуем повторить такие же действия, что и для примера №1:

Разбор полетов, или почему так происходит

Вернемся к 1ому примеру

Как мы теперь видим, сборщик мусора может запустится на 3ем шаге, но что же произойдет если он не запустится? Ведь при стандартных настройках шанс на запуск всего 1 из 1000.
Устаревшая сессия успешно откроется, прочитается, а в конце работы сохранится и время последнего обращения к файлу будет обновлено — в этом случае такая сессия становится почти бесконечной. Но, в тоже время, если наш скрипт использует 1000 разных пользователей, то о «бесконечности» сессии можно забыть, т.к. GC скорее всего запустится у кого либо из пользователей, время жизни начнет работать верно(точнее почти верно). Такое поведение системы неоднозначно и непредсказуемо, а это потенциально приведет к большому количеству трудно отлавливаемых проблем.

Читайте также:  Как узнать размер страницы html

И что теперь делать, или выходы из ситуации

Самым верным решением, является использования своего механизма валидации сессии. В документации явно сказано что
«session.gc_maxlifetime задает отсрочку времени в секундах, после которой данные будут рассматриваться как „мусор“ и потенциально будут удалены. Сбор мусора может произойти в течение старта сессии (в зависимости от значений session.gc_probability и session.gc_divisor).» Слова «потенциально» и «может», как раз и говорят о том, что gc не предназначен для ограничения времени жизни сессии. В тех местах, где время жизни сессии важно, а возникновение артефактов, как из примера №2 критично, используйте свою валидацию времени жизни.

Выход №2, плохой и неправильный

Мы знаем, что установленный «принудительный режим» работы gc отработает на шаге №3 старта сессии. Т.е. фактически после старта устаревшей сессии данные в массиве $_SESSION присутствуют, а файл уже удален. В таком случае логично попробовать пересоздать сессию, т.е фактически сделать запуск 2 запуска session_start:

 else < $_SESSION['value'] = 0; >echo $_SESSION['value']; session_commit(); session_start(); echo ' '.$_SESSION['value']; ?>

Это поведение ясно из порядка обработки сессии, но(вспомним документацию, да и вообще взглянем адекватно) делать так не стоит.

Ура, разобрались — вывод

Меня удивило, что большинство, даже опытных, разработчиков ни разу не задумывались о поведении GC, беззаботно доверяя ему ограничение времени жизни сессии. При том что в документации явно указано, что делать этого не стоит, а название Garbage Collector(не Session Validator, или Session Expire) говорит само за себя. Ну а главный вывод, конечно, заключается в том, что следует тщательно проверять, даже кажущиеся очевидными части системы. Ошибки системных функций или методов иногда являются их неверной трактовкой, а не ошибками как таковыми.

Всем спасибо за то, что дочитали до конца. Надеюсь, что эта статья оказалась для вас полезной.

Источник

Оцените статью