Хранение сессий в Memory Storage Engine и переполнение кучи (heap)

Сегодня речь порйдёт об интересных граблях с авторизацией на сайте. Хранение сессий у нас реализовано в БД, с помощью Zend_Session_SaveHandler_DbTable. Это очень удобно, т.к. быстрее чем хранение в виде файлов, и нагляднее. Так вот, сегодня при авторизации вдруг стало выдаваться сообщение: Error: Zend_Session is currently marked as read-only. Также очень часто вылетала вот эта ошибка: Exception thrown without a stack frame in Unknown on line 0

“Хм, что бы это могло быть” подумал я. Сначало я подумал, что что-то не так с самим Zend Framework, посмотрел где возникает ошибка, и увидел следующий код:

При работе на продакшене, следующий код вызывал фатальную ошибку. Оказывается, что флаг записи стоит в FALSE. Начал выяснять почему он такой, и в каком месте он устанавливается в TRUE.

if (self::$_throwStartupExceptions) {
require_once ‘Zend/Session/Exception.php’;
set_error_handler(array(‘Zend_Session_Exception’, ‘handleSessionStartError’), $errorLevel);
}

$startedCleanly = session_start();

parent::$_writable = true;

См. Zend_Session, строка 472

После гугления выяснилось, что в самом ErrorHandler’е вызывается исключение, что вызывает такую реакцию системы. Дальше мне было интересно посмотреть, а что же находится в таблице с сессиями. Посмотрев в неё, я был немного ошарашен, т.к. она собержала более 3000 записей. После очистки таблицы баг исчез.

Тут надо упомянуть, что в качестве движка хранения для этой таблицы у нас используетс я MEMORY storage engine. А он хранит данные в куче (HEAP), объем которой ограничен параметром MySQL “max_heap_table_size“.

Посмотреть значение этой переменной можно с помошью запроса “show

А установить с помощью вот этого запроса:

Количество памяти, необходимой для хранения данных таблицы можно посчитать по следующей формуле:

  • The memory needed for one row in a MEMORY table is calculated using the following expression:

    ALIGN() represents a round-up factor to cause the row length to be an exact multiple of the char pointer size. sizeof(char*) is 4 on 32-bit machines and 8 on 64-bit machines.

Вообще, рекомендую вам почитать про Memory storage Engine на сайте MySQL.

2 Comments

    1. Слышал много хороших отзывов, но не пробовал.
      Хочу попробовать HandlerSocketSession.php из поставки http://code.google.com/p/php-handlersocket. Тоже самое NoSQL хранение сессий и быстрый доступ 🙂

Leave a Comment