воскресенье, 20 июля 2014 г.

Хранение сессии в базе данных

В список моих рабочих обязанностей входит поддержка одного из наших внутренних сервисов, написанного с использованием Yii Framework.

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

Причина - приличный набор данных, который в ней хранится. Дело в том, что при авторизации пользователя, в сессию сохраняются некоторые данные о нем, список его прав (RBAC) и прочие данные приложения (какие-то массивы, переменные и прочее).

Поддержка есть поддержка, а на перепиливание кучи логики приложения нет ни времени ни желания. Как раз на днях прочитал вот тут о том, что в Yii есть готовое решение для хранения сессий в базе данных. Класс CDbHttpSession. Также, в мануале фреймворка есть рецепт, который предлагает использовать его в своем приложении для увеличения производительности.

Решено опробовать, тем более что делается это очень просто. В файл конфига в раздел components вставляем код:

     'session' => [
             'class' => 'system.web.CDbHttpSession',
             'connectionID' => 'db',
             'autoCreateSessionTable' => true, // default
     ],

Индекс по полю expired - рекомендация от разработчиков Yii, доступна по ссылке выше. Также нам рекомендуют после первого запуска установить параметр autoCreateSessionTable = false, чтобы отключить проверку существования таблицы.

Подключаю - улыбаюсь. Действительно, сессия теперь стартует практически моментально.
Почему так? Причины две:

  1. скорость чтения (чтение из базы быстрее чтения из файла)
  2. чтение из файла блокирует файл, пока не закончит с ним работать (если время чтения из файла при обработке запроса будет превышать время до следующего поступившего запроса, ему придется ждать завершения)
Если же вы активно используете кэширование, вам также подойдет класс CCacheHttpSession. Но здесь нужно быть осторожным, т.к. кэш может затираться раньше положенного времени. Как следствие - сессии будут внезапно обрываться.

P.S.
Чуть позже, на нашем основном проекте, тоже стали хранить сессии в базе данных из-за тормозов, связанных с увеличением количества пользователей и генерируемыми ими AJAX-запросами. Они используются у нас из JS по таймауту для актуализации контента на странице. Да, решение устаревшее и требует пересмотрения, но как временная мера компонент CDbHttpSession подошел идеально. После активации ресурс просто ожил.