Подтвердить что ты не робот

Как хранить сеансы PHP в кэше APC?

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

4b9b3361

Ответ 1

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

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

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

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

Нижняя строка: избегайте этого, это не сработает.

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

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

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

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

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

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

Memcache (г)

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

Ответ 2

<?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);
    }
}

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

Ответ 7

Другим хорошим решением является хранение сеансов PHP в memcached

session.save_handler = memcache

Ответ 8

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

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