Сессии в PHP и нагрузка на сервер
На первый взгляд кажется, что работать с сессиями в PHP предельно просто. Достаточно написать где-нибудь в начале скрипта такой код:
session_name('MySessId'); // задаем имя cookie или параметра, в котором хранится идентификатор сессии
session_set_cookies_params(24*3600,'/','xpro.su'); //если нужно, задаем домен, путь и время хранения для cookie сессии
session_start(); // а теперь запускаем саму сессию
и в глобальной переменной $_SESSION можно будет хранить нужные значения, которые будут доступны при каждом обращении пользователя к странице! На малых сайтах такое решение работает без проблем, но оно не будет масштабируемым: как только сайт достигнет нескольких десятков тысяч страниц или посещаемости в десятки тысяч пользователей в сутки, может случиться так, что сайт будет открываться весьма и весьма медленно.
Чтобы разобраться, почему такое происходит, рассмотрим, как же работают сессии в PHP. При вызове session_start в самый первый раз генерируется ее идентификатор сессии, который передается пользователю либо в виде cookie, либо в виде параметра URL, который добавляется ко всем локальным ссылкам на странице, выдаваемой пользователю. На сервере же создается файл, имя которого совпадает с этим идентификатором. В конце выполнения скрипта (или при вызове session_write_close()) данные, помещенные в $_SESSION, сериализуются и записываются в этот файл. Когда пользователь следующий раз обращается к скрипту, то от него либо в cookies, либо в параметрах запроса передается идентификатор сессии (в приведенном выше примере этот параметр будет называться MySessId), проверяется, существует ли файл сессии с таким именем, и если да, происходит его блокировка, считывание и десериализация, после чего данные, сохраненные при прошлом вызове, снова попадают в $_SESSION.
Поисковые роботы при индексации сайта не сохраняют установленные сайтом cookies или параметры с идентификатором сессии. В результате каждое обращение поискового робота к любой странице сайта будет приводить к создании новой сессии с новым идентификатором. То есть, если сайт содержит десять тысяч страниц, то будет создано десять тысяч файлов сессий! В результате даже простое открытие файла из каталога с таким количеством файлом становится весьма и весьма медленной операцией. Если проект работает на отдельном сервере, частично эту проблему можно решить, задав в настройках PHP хранение сессий не в файлах, а в СУБД или shared memory, но все равно нагрузка будет достаточно существенная из-за операций блокировки и сериализации. Также если разрешена передача идентификатора сессии через GET-запрос, поисковые системы запоминают URL с этим параметром, что тоже создает определенные проблемы (хотя Яндекс и Google вроде бы сейчас научились обнаруживать и отбрасывать идентификатор).
Но всегда ли нужно создавать сессию прямо при первом же обращении пользователя к странице? Для большинства проектов это не так. Например, на форуме необходимость сессии возникает тогда, когда пользователь решает войти под своим именем, а в Интернет-магазине — при добавлении товара в корзину. До этого для показа тем в гостевом режиме или описаний товаров сессия совершено не требуется. Отсюда вывод: сессию пользователя нужно создавать только тогда, когда в ней возникает реальная необходимость. Но с другой стороны, если пользователь вошел на сайт или добавил что-то в корзину, то нужно на каждой странице показывать ему, что форум его узнал или что в корзине у него что-то есть. Таким образом алгоритм действий получается такой: не создаем сессию, пока она нам не потребовалась, но если уж создали, то возобновляем ее (т.е. читаем ее данные в $_SESSION) при каждом обращении к скрипту. Для его реализации подойдет следующая функция:
function session($force=false) {
$s_name='MySessId'; // имя сессии
static $started;
session_name($s_name);
session_set_cookie_params(24*60*60,'/','xpro.su'); // параметры cookies
/* Если от пользователя пришел параметр или cookie с идентификатором сессии,
значит, сессию уже создали и нужно ее возобновить,
если же $force==true, то это явное указание на необходимость создания сессии */
if (isset($_REQUEST[$s_name]) || isset($_COOKIE[$_name]) || $force) {
/* Переменная $started нужна для избежания повторного вызова session_start
(например, если добавляем в корзину еще один товар при уже созданной сессии),
чтобы не генерировалось лишнее предупреждение. */
if (!$started) { session_start(); $started=1; }
}
}
В скрипте эту функцию нужно вызывать дважды: с параметром false в начале скрипта для восстановления сессии, если она уже была создана, и с параметром true при выполнении тех действий, которые требуют обязательного создания сессии (вход пользователя на форум, добавление товара в корзину и т.п.).
Знание таких особенностей и использование предложенной функции позволит не только снизить нагрузку при прохождении по сайту поисковых роботов, но и сэкономить при этом по несколько сотен байтов на каждый запрос, так как без необходимости не будет передаваться заголовок Set-cookie или параметры с идентификатором сессии.
http://php.net/manual/ru/function.session-status.php
Во-вторых, вместо страдания вокруг ручного вызова самопальной функции в сотне мест приложения достаточно в инициализационном коде вызвать session_save_path() с указанием на директорию, имя которой строится исходя из текущей даты в зависимости от загрузки ресурса. То есть, каждый час/сутки/месяц создавать новую директорию и делать хард-линки на файлы сессий из предыдущей директории. Правда, механизм очистки сессий придется реализовывать самостоятельно, но уж лучше все что касается сессии собрать в одном месте, чем размазывать по коду вызовы 'session()'
http://php.net/manual/ru/function.session-save-path.php