Сессии в 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 или параметры с идентификатором сессии.