Как хранить сессии PHP в APC Cache? - PullRequest
20 голосов
/ 12 ноября 2009

Хранение сессий на диске очень медленное и болезненное для меня. У меня очень высокий трафик. Я хочу сохранить сеанс в Advanced PHP Cache, как я могу это сделать?

Ответы [ 9 ]

17 голосов
/ 04 августа 2012
<?php

// to enable paste this line right before session_start():
//   new Session_APC;
class Session_APC
{
    protected $_prefix;
    protected $_ttl;
    protected $_lockTimeout = 10; // if empty, no session locking, otherwise seconds to lock timeout

    public function __construct($params=array())
    {
        $def = session_get_cookie_params();
        $this->_ttl = $def['lifetime'];
        if (isset($params['ttl'])) {
            $this->_ttl = $params['ttl'];
        }
        if (isset($params['lock_timeout'])) {
            $this->_lockTimeout = $params['lock_timeout'];
        }

        session_set_save_handler(
            array($this, 'open'), array($this, 'close'),
            array($this, 'read'), array($this, 'write'),
            array($this, 'destroy'), array($this, 'gc')
        );
    }

    public function open($savePath, $sessionName)
    {
        $this->_prefix = 'BSession/'.$sessionName;
        if (!apc_exists($this->_prefix.'/TS')) {
            // creating non-empty array @see http://us.php.net/manual/en/function.apc-store.php#107359
            apc_store($this->_prefix.'/TS', array(''));
            apc_store($this->_prefix.'/LOCK', array(''));
        }
        return true;
    }

    public function close()
    {
        return true;
    }

    public function read($id)
    {
        $key = $this->_prefix.'/'.$id;
        if (!apc_exists($key)) {
            return ''; // no session
        }

        // redundant check for ttl before read
        if ($this->_ttl) {
            $ts = apc_fetch($this->_prefix.'/TS');
            if (empty($ts[$id])) {
                return ''; // no session
            } elseif (!empty($ts[$id]) && $ts[$id] + $this->_ttl < time()) {
                unset($ts[$id]);
                apc_delete($key);
                apc_store($this->_prefix.'/TS', $ts);
                return ''; // session expired
            }
        }

        if (!$this->_lockTimeout) {
            $locks = apc_fetch($this->_prefix.'/LOCK');
            if (!empty($locks[$id])) {
                while (!empty($locks[$id]) && $locks[$id] + $this->_lockTimeout >= time()) {
                    usleep(10000); // sleep 10ms
                    $locks = apc_fetch($this->_prefix.'/LOCK');
                }
            }
            /*
            // by default will overwrite session after lock expired to allow smooth site function
            // alternative handling is to abort current process
            if (!empty($locks[$id])) {
                return false; // abort read of waiting for lock timed out
            }
            */
            $locks[$id] = time(); // set session lock
            apc_store($this->_prefix.'/LOCK', $locks);
        }

        return apc_fetch($key); // if no data returns empty string per doc
    }

    public function write($id, $data)
    {
        $ts = apc_fetch($this->_prefix.'/TS');
        $ts[$id] = time();
        apc_store($this->_prefix.'/TS', $ts);

        $locks = apc_fetch($this->_prefix.'/LOCK');
        unset($locks[$id]);
        apc_store($this->_prefix.'/LOCK', $locks);

        return apc_store($this->_prefix.'/'.$id, $data, $this->_ttl);
    }

    public function destroy($id)
    {
        $ts = apc_fetch($this->_prefix.'/TS');
        unset($ts[$id]);
        apc_store($this->_prefix.'/TS', $ts);

        $locks = apc_fetch($this->_prefix.'/LOCK');
        unset($locks[$id]);
        apc_store($this->_prefix.'/LOCK', $locks);

        return apc_delete($this->_prefix.'/'.$id);
    }

    public function gc($lifetime)
    {
        if ($this->_ttl) {
            $lifetime = min($lifetime, $this->_ttl);
        }
        $ts = apc_fetch($this->_prefix.'/TS');
        foreach ($ts as $id=>$time) {
            if ($time + $lifetime < time()) {
                apc_delete($this->_prefix.'/'.$id);
                unset($ts[$id]);
            }
        }
        return apc_store($this->_prefix.'/TS', $ts);
    }
}
10 голосов
/ 12 ноября 2009

Теоретически вы должны иметь возможность написать пользовательский обработчик сеанса , который использует APC, чтобы сделать это прозрачно для вас. Тем не менее, я не смог найти ничего действительно многообещающего в быстром пятиминутном поиске; кажется, что большинство людей используют APC для кэширования байт-кода и помещают свои сессии в memcached.

9 голосов
/ 09 декабря 2012

Я пытался привлечь лучшие ответы, предлагая 100 баллов в качестве награды, но ни один из ответов не был действительно удовлетворительным.

Я бы суммировал рекомендуемые решения следующим образом:

Использование APC в качестве хранилища сеансов

APC действительно нельзя использовать в качестве хранилища сеансов, поскольку для APC нет механизма, который бы позволял надлежащую блокировку, но эта блокировка необходима для того, чтобы никто не изменил первоначально прочитанные данные сеанса перед их записью.

Итог: избегайте, это не сработает.

Альтернативы

Может быть доступно несколько обработчиков сеансов. Проверьте вывод phpinfo() в Session разделе «Зарегистрированные обработчики сохранения».

Хранение файлов на RAM-диске

Работает "из коробки", но по понятным причинам требует файловую систему, смонтированную как RAM-диск.

Общая память (мм)

Доступно, когда PHP скомпилирован с включенным mm. Это встроено в Windows.

* +1025 * Memcache (д) * * тысячу двадцать-шесть

PHP поставляется с выделенным обработчиком сохранения сеанса для этого. Требуется установленный сервер memcache и клиент PHP. В зависимости от того, какое из двух расширений memcache установлено, обработчик сохранения называется либо memcache, либо memcached.

.
9 голосов
/ 05 декабря 2012

Простое размещение диска / tmp (или там, где хранятся файлы сеансов PHP) на RAM-диске, таком как tmpfs или ramfs, также может привести к серьезному повышению производительности и будет намного более прозрачным переключателем с нулем изменения кода.

Увеличение производительности может быть значительно меньше, но все равно будет значительно быстрее, чем сеансы на диске.

3 голосов
/ 06 декабря 2012

Храните его в файлах cookie (в зашифрованном виде) или MongoDB. APC не предназначен для этой цели.

2 голосов
/ 07 декабря 2012

Явное закрытие сессии сразу после запуска, открытия и записи сеанса должно решить проблему блокировки в ответе Unirgy (где доступ к сеансу всегда циклический (начало / открытие-запись-закрытие). Я также представляю второй класс - APC_journaling или что-то подобное в сочетании с Sessions в конечном итоге было бы лучше .... Сессия начинается и записывается с уникальным внешним идентификатором, назначенным для каждого сеанса, этот сеанс закрывается, и открывается журнал (массив в кэше apc через _store & _add) / создан для любых других операций записи, предназначенных для перехода в сеанс, которые затем могут быть прочитаны, проверены и записаны в сеанс (идентифицированный этим уникальным идентификатором!) в apc при следующей удобной возможности.

Я нашел хороший пост в блоге, объясняющий, что блокирующий хаос, на который ссылается Свен, приходит от блокирования сеанса до его закрытия или до завершения выполнения скрипта. Сеанс, который немедленно закрывается, не мешает чтению только записи. http://konrness.com/php5/how-to-prevent-blocking-php-requests - ссылка на пост в блоге. Надеюсь, это поможет.

2 голосов
/ 07 декабря 2012

Другое хорошее решение - хранить сессии PHP в memcached

session.save_handler = memcache

2 голосов
/ 07 декабря 2012

Вы можете хранить свои данные сеанса во внутренней памяти PHP.

session.save_handler = mm

Но это должно быть доступно: http://php.net/manual/en/session.installation.php

0 голосов
/ 14 января 2014

Кэширование внешних данных в PHP

Ссылка на учебник - http://www.gayadesign.com/diy/caching-external-data-in-php/


Как использовать кэширование APC с PHP

Ссылка на учебник - http://www.script -tutorials.com / how-to-use-apc-caching-with-php /

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...