Сохранение всей активности пользователя в виде значений сеанса и сохранение значений сеанса в конце сеанса - PullRequest
4 голосов
/ 26 ноября 2011

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

  • Теперь я думаю о сохранении всего этого как значений сеанса и выполнение запроса в конце сеанса .Но я не знаю, как я могу обработать это событие «конец сеанса» в php.

Я думал о фоновом процессе, который хранит все значения сеанса непосредственно перед тайм-аутом сеанса, но я неЯ ничего не знаю о многопоточных методах в php, хотя я слышал, что возможны некоторые обходы.

  • Я бы хотел определить, неактивен ли пользователь без триггера пользователя (например, загрузка страницы) и сохраните все значения сеанса в конце сеанса до истечения времени ожидания.

Это позволит сэкономить некоторую рабочую нагрузку на ядре базы данных, например, так: пользовательпросматривая много страниц, я увеличиваю значение в сеансе, вместо того, чтобы выполнять запрос типа

update pageviews set numberofviews=numberofviews+1

для каждой загрузки страницы.

  • вопрос такой: " Как можноЯ обрабатываю событие окончания сеанса в php без активности пользователя ? "

Решения реальной проблемы также приветствуются.независимо от значимости вопроса, выделенного жирным шрифтом.(Я не начал писать код для этого, мой вопрос не об исправлении ошибок.)

Возможные решения:

Я обнаружил функцию php обработчик сессии , но документация ничего не говорито том, может ли он иметь нулевые параметры для параметров обратного вызова?

Потеряю ли я стандартную функциональность, если введу нулевые параметры для параметров $ callback?

Я только хочу изменить событие сеанса $ destroy.Мне нужна помощь в этом, сейчас.

Соответствующие сообщения: RP1

Ответы [ 8 ]

3 голосов
/ 26 ноября 2011

Вы действительно не можете использовать обработчик session_destroy, так как он вызывается, только если вы явно вызываете session_destroy, что не произойдет, если пользователь просто закроет свой браузер и завершит сеанс.Так как в этом сценарии нет способа зафиксировать «событие» окончания сеанса, вам придется вместо этого выполнять какую-то периодическую проверку, чтобы увидеть, был ли сеанс бездействующим в течение заданного периода времени.Самый простой способ сделать это - создать в сеансе поле с последним временем доступа, а затем создать скрипт, который периодически (либо через cron, либо запускает некоторые другие функции в ваших PHP-скриптах) проверяет это поле для всех активных сеансов и,для любого, у которого метка времени старше xx секунд, запустите ваш запрос на обновление.

Обратите внимание, что для того, чтобы сделать это, используя стандартные сеансы PHP, которые хранятся в файловой системе, вам нужно будет фактически открыть файлы иразбирать их напрямую.Альтернативой является сохранение сессий в базе данных, но это, вероятно, не то, что вы хотите сделать, учитывая тот факт, что вы пытаетесь уменьшить нагрузку на БД.

Еще одна возможность, которая не совсем так, как разработкаинтенсивность:

  1. Добавление последней отметки времени к сеансу
  2. Проверка этой отметки времени при каждом обновлении сеанса
  3. Если отметка времени старше хх секундзапустите запрос на обновление базы данных и установите временную метку на текущее время.

Таким образом, вы обновляете базу данных очень часто, а не каждую загрузку страницы.Недостатком этого подхода, конечно, является то, что если последнее действие в сеансе не соответствует точно временному интервалу, который вызывает функцию обновления, вы не можете хранить самую актуальную информацию о сеансе в БД.

2 голосов
/ 26 июня 2012

Это не то, для чего были созданы сеансы, поэтому то, чего вы пытаетесь достичь, невозможно только с помощью механики сеансов.

При стандартных сеансах PHP ваши возможности несколько ограничены и зависят от хранилища сеансов:

  1. По умолчанию сессии хранятся в файлах. Если вы отключите сборку мусора в сеансе, вы можете запустить задание cron, которое будет анализировать файлы сеансов старше указанного вами времени. Это не идеально, но, безусловно, самое простое. Также файл сессий отстой - пиши каждый запрос.
  2. Сессии в Memcached. Без хорошего способа извлечения записей старше x и того факта, что Memcached будет просто отбрасывать данные, когда срок их действия истекает, можно сделать немного.
  3. Сеансы в БД - у вас уже есть обновление для каждого запроса.

Так что ваши варианты со стандартными сессиями в лучшем случае ограничены. Моя рекомендация: замените стандартный сеанс своим собственным, но это означает, что вы больше не будете получать доступ к сеансу через $ _SESSION и потребует от вас переписать большую часть кода.

Я заменил обычный сеанс на одноэлементный, который хранит данные сеанса в APC / Memcached, а также в БД. Данные сеанса сохраняются в БД, только если я запрашиваю их (Session::persistentStore($key,$value)) или если во время обработки запроса сохраненные данные сеанса APC / Memcached указывают, что они не были записаны в течение достаточно длительного времени. Это ограничивает количество записей много. С помощью этой замены вы бы просто принудительно сохраняли сеанс со стороны БД: извлекали идентификаторы сеансов, которые не обновлялись в течение x минут из базы данных, извлекали информацию из APC / Memcached для каждого из них, и если там нет информации об обновлении либо (с указанием того, что сессия скоро закончится) сохраните его в БД.

1 голос
/ 29 июня 2012

Вы говорите о задержке записи статистики и управлении сессиями.Ваша настоящая проблема, я полагаю, состоит в том, чтобы избежать запросов на запись по http-запросам в базу данных.

Некоторые подсказки, которые могут быть полезны для таких проблем:

  1. Будьте осторожны с параллельный доступ в сеансе .Обычно мы думаем, что сеанс доступен только одному процессу, но это неправильно, скажем, например, вы выполняете многофайловую загрузку, когда некоторые js открывают несколько ajax-запросов к серверу, каждый процесс использует один и тот же сеанс.То же самое, когда вы открываете 10 вкладок на одном веб-сайте с помощью браузера.
  2. Добавление запросов на обновление для каждого запроса - это тяжелая вещь .Запросы выбора выполняются быстро и обычно используют какой-то кэш на стороне SQL.Запросы обновления медленные, могут перестраивать индексы и обычно подразумевают некоторую очистку кэша на сервере SQL.Они также могут подразумевать другой сеанс SQL, если вы используете разных пользователей в базе данных только для чтения или для чтения и записи.
  3. размер сеанса не должен быть слишком большим, так каксеанс должен быть загружен для каждого запроса, и каждый раз, когда вы записываете что-то в своем сеансе, устанавливается механизм lock (из-за 1), и данные передаются в физическое хранилище сеансов(файл по умолчанию).Таким образом, запись сеанса замедляет ваш процесс.
  4. Бэкэнд NoSQl, такой как MongoDb или Reddit , может быть хорошим местом для хранения статистики по запросу, у них естьправильные инструменты для обеспечения атомарных обновлений, блокировок и могут работать действительно быстрее, чем реляционная база данных (но вы также можете проверить производительность таблиц памяти в реляционной базе данных).Таким образом, вы можете использовать эти инструменты для отслеживания активности и избегать обновлений SQL, используя эти серверные бэкэнды в качестве основной цели для оперативной статистики.И вы можете асинхронно собрать некоторую статистику из этих серверных частей для вашей базы данных.Теперь сеансы являются временными объектами, и тезисы NoSQl также могут быть хорошими хранилищами сеансов (если вы пишете свои собственные обработчики хранилищ сеансов).

EDIT: примерпроблем атомарного обновления с параллельным использованием: выполнение запроса с приращением counter = counter + 1 - это то же самое, что чтение счетчика, его приращение и выполнение запроса на обновление counter = mynewvalue ,Второй вариант неверен, когда несколько процессов используют одни и те же данные.

1 голос
/ 26 июня 2012

Я думал о фоновом процессе, который хранит все значения сеанса незадолго до тайм-аута сессии, но я ничего не знаю о многопоточные методы в php, хотя я слышал некоторые возможно обойти.

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

  1. Не требует многопоточности
  2. написать задание cron, которое выполняется каждую минуту / 5 минут
    • выбирает все записи, срок действия которых истекает
    • сохраняет их в другой таблице

ключ использует задание cron и не пытается обработать событие expiration в середине потока по запросу http

1 голос
/ 25 июня 2012

Какую проблему вы пытаетесь решить? Я не понимаю, почему вы не запускаете запрос на обновление базы данных при каждом запросе. Это не должно занять намного больше времени, чем 0,0001 с.

Я бы определенно шел за обновлением каждого запроса. Это 1 строка кода, не создающая чрезмерной нагрузки на базу данных и намного более эффективная.

Ваш предложенный метод сложно протестировать, он создает нежелательную нагрузку и может даже создавать глобальное состояние. Вы можете предотвратить все это, просто перейдя к традиционному решению. Сессии (...), когда дело доходит до определения, когда они «закончились».

1 голос
/ 25 июня 2012

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

1 голос
/ 24 июня 2012

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

0 голосов
/ 26 ноября 2011

Немного не в порядке, но вы можете сделать свою собственную сборку мусора.

  • использовать PHP для сохранения сеансов в каталоге, предпочтительно tmpfs, с отключенной сборкой мусора.

  • написать периодический скрипт PHP, чтобы найти все файлы сеансов старше 20 минут, открыть их, записать их в базу данных и удалить их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...