PHP & Sessions: есть ли способ отключить блокировку сеанса PHP?

Есть ли способ отключить блокировку сеанса в PHP при использовании обработчика сеанса по умолчанию?

[EDIT:] Или есть, по крайней мере, способ перезапустить сеанс после вызова session_write_close()? session_start() не работает, если какой-либо вывод уже отправлен в браузер.

Ответ 1

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

Вместо этого закройте сеанс очень рано, если вы знаете, что не собираетесь писать ему в этом запросе. После его запуска вы сможете прочитать его для всего запроса (если вы не заново запустите его или не сделаете некоторые другие специальные вещи) даже после вызова session_write_close. Итак, что бы вы сделали, это проверить запрос, чтобы увидеть, является ли он запросом на запись, а если нет, просто закройте его сразу после его открытия. Обратите внимание, что это может иметь некоторые неблагоприятные последствия, если вы позже попытаетесь написать сеанс (для защиты Captcha или CSRF или что-то еще), поэтому используйте с осторожностью...

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

Ответ 2

У меня была страница отчета, которая заняла более 2 минут (более 80 запросов AJAX). Я отключил сессионную блокировку до 30 секунд. Да, не дай бог, вы удаляете блокировку файлов, потому что тогда у вас есть условия гонки. И если вы не понимаете условия гонки, и вы не знаете, какой эффект будет на ваших сеансах... затем НЕ удаляйте блокировку файлов. Однако, если вы, зная, какие данные на ваших сеансах и зная, какие условия гонки считают, считают, что нет данных, которые могут быть подвергнуты неблагоприятному воздействию условий гонки, что создаст ошибку... вы знаете, что ваша среда лучше, чем кто-то еще делает, так что идите на это.

MySQL, REDIS и Memcache

Кроме того, обратите внимание, что если вы переключитесь на MySQL для управления сеансом, существует 99% -ный шанс, IMHO, что вы НЕ блокируете строку с момента, когда вы читаете, до момента написания. Таким образом, используя MySQL, у вас все еще есть те же условия гонки (или проблемы с блокировкой, если вы решили заблокировать строку).

На основе информации, которую я смог найти, люди, которые используют PHP Redis, используют неблокирующее приложение, которое подвержено условиям гонки... согласно следующей теме... и они приводят скорость как одну из причин, по которым они как эта "функция":

https://github.com/phpredis/phpredis/issues/37

Memcached не поддерживал блокировку сеанса до версии 3.0.4... поэтому он также был - изначально - подвержен условиям гонки.

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

В конечном счете проблема

ВСЕ параллельные запросы будут ВСЕГДА подчиняться условиям гонки БЕЗ ОШИБКИ, вы блокируете блокировку файлов, после чего они больше не являются параллельными запросами.

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

Лучший вариант

Однако для одновременных запросов лучше использовать API без сеанса. Однако, если у вас нет времени на реорганизацию такого API... затем чтение.

Решение Stop-Gap для хранения файлов сеансов PHP и остановки блокировки

Чтобы продолжить использование сеансов PHP по умолчанию, чтобы остановить блокировку и в основном иметь очень быстрое решение сложной проблемы, вы можете реализовать реализацию примера PHP на сайте SessionHandler.

У меня есть код ниже в рабочей среде для сайта с десятками тысяч подключений в минуту, и у меня еще не было проблем с условиями гонки, но я также не храню данные, состояние может сломаться. Этот код, как я уже сказал, получил один отчет более 2 минут до менее 30 секунд... и потребовалось несколько минут для реализации. Нет схемы MySQL для создания, не Memcache или Redis для установки.

Это письмо, пример реализации, представленный в документации PHP (http://php.net/manual/en/class.sessionhandlerinterface.php), и он не блокирует сеанс файл, когда он его читает.

<?php
class MySessionHandler implements SessionHandlerInterface
{
    private $savePath;

    public function open($savePath, $sessionName)
    {
        $this->savePath = $savePath;
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0777);
        }

        return true;
    }

    public function close()
    {
        return true;
    }

    public function read($id)
    {
        return (string)@file_get_contents("$this->savePath/sess_$id");
    }

    public function write($id, $data)
    {
        return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
    }

    public function destroy($id)
    {
        $file = "$this->savePath/sess_$id";
        if (file_exists($file)) {
            unlink($file);
        }

        return true;
    }

    public function gc($maxlifetime)
    {
        foreach (glob("$this->savePath/sess_*") as $file) {
            if (filemtime($file) + $maxlifetime < time() && file_exists($file)) {
                unlink($file);
            }
        }

        return true;
    }
}

В PHP 5.4+ использование его так же просто, как установка обработчика перед началом сеанса:

$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();

Для более низких версий PHP вы все равно можете делать это через вызовы функций... см. документы PHP.

Ответ 3

Вы можете перезапустить сеанс, вызвав session_start() после session_write_close(). Однако это вызовет появление нескольких малых островных развивающихся государств. Я разрешаю это, удаляя несколько SIDS из заголовка до того, как выйдет поток.

Смотрите этот пример: https://gist.github.com/CMCDragonkai/6912726#file-nativesession-php-L254

Ответ 4

Кроме использования session_write_close()? Нет, о которых я знаю.

Ответ 5

Невозможно отключить блокировки из сеансов php. Это реальный случай использования блокировки. Только способ избавиться от сеансов и/или php. В качестве временного решения вы можете использовать обработчик сеанса riak: https://github.com/zacharyfox/riak-php-sessions он блокируется, и он работает.

В последних версиях обработчика сеанса memcached также вводится блокировка для некоторых безумных причин и нет способа отключить его.

Ответ 6

Если PHP не обрабатывает запросы асинхронно даже после вызова session_write_close, это может быть просто xdebug. Я не знаю, является ли это вашей проблемой, но я все время спотыкаюсь от этого и сводил меня с ума из-за этого, поэтому я думал, что опубликую его, если кто-то еще будет иметь такую ​​же проблему:)

Ответ 7

Это довольно старый вопрос, который я обнаружил при исследовании обработчиков сеансов, однако ответ да, это возможно - но не использовать обработчик по умолчанию (без глубокого взлома в файловую систему, чтобы отключить блокировку).

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

Мое решение является частью большего расширения механизма обработки сеанса - Stackable Session Handler, который включает хранилище, совместимое с обработчиком по умолчанию и ( необязательно) неблокирующее чтение и запись сеанса.