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

// Декабрь 27th, 2010 // MySQL, PHP, Zend Framework

Сегодня речь порйдёт об интересных граблях с авторизацией на сайте. Хранение сессий у нас реализовано в БД, с помощью 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

max_error_count            | 64
max_heap_table_size        | 16777216
max_insert_delayed_threads | 20

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

mysql> SET max_heap_table_size = 1024*1024;
Query OK, 0 rows affected (0.00 sec)

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

  • The memory needed for one row in a MEMORY table is calculated using the following expression:
    SUM_OVER_ALL_BTREE_KEYS(max_length_of_key + sizeof(char*) × 4)
    + SUM_OVER_ALL_HASH_KEYS(sizeof(char*) × 2)
    + ALIGN(length_of_row+1, sizeof(char*))
    

    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.

Share

Спасибо!


Если вам помогла статья, или вы хотите поддержать мои исследования и блог - вот лучший способ сделать это:


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

Комментировать