session_start()需要非常长的时间

时间:2021-07-27 07:20:55

Mys site works very slowly (and I didn't have any idea about why). It is based on Zend Application, I used to make about tens of such sites, so I'm sure that MY code is OK.

Mys网站工作非常缓慢(我对其原因一无所知)。它基于Zend应用程序,我曾经制作了大约几十个这样的网站,所以我确信我的代码没问题。

I installed xdebugger on server, tried to profile it and guess what? php::session_start() took 48.675 seconds. Fourty Eight and a Half Seconds! It's unbelievable! What could be the reason of this? It's common operation, why could it execute SO long? How to fix such behaviour, which configs to edit? Searched over Google, but found no good answer (almost everywhere there's a question, but no answer). Thanks in before!

我在服务器上安装了xdebugger,试图对其进行分析并猜测是什么? php :: session_start()花了48.675秒。四十八秒半!这太不可思议了!这可能是什么原因?这是常见的操作,为什么它可以执行SO很长时间?如何修复这种配置编辑的行为?通过谷歌搜索,但没有找到好的答案(几乎所有地方都有问题,但没有答案)。谢谢你!

session_start()需要非常长的时间

8 个解决方案

#1


18  

session_start (with sessions stored in files) is blocking in PHP, so this issue will appear if you try to start several server sessions for the same browser session (AJAX or multiple browser tabs/windows). Each session_start will wait until the other sessions have been closed.

session_start(会话存储在文件中)在PHP中是阻塞的,因此如果您尝试为同一浏览器会话(AJAX或多个浏览器选项卡/窗口)启动多个服务器会话,则会出现此问题。每个session_start将等待其他会话关闭。

See here: http://konrness.com/php5/how-to-prevent-blocking-php-requests/

见这里:http://konrness.com/php5/how-to-prevent-blocking-php-requests/

Try changing from files to database storage of sessions.

尝试从会话的文件更改为数据库存储。

#2


18  

My guess would be the garbage collection routine, which gets run inside of the native session_start() function. Maybe you've done something that keeps many old session files around, like changed the max life time? Or maybe you've decided it would be a good idea to store them in a database, but forgot to create a suitable index? The native GC routine stat()'s every single session file to check for expiration. This is time consuming if there's a lot of files built up.

我的猜测是垃圾收集例程,它在本机session_start()函数中运行。也许你做过一些可以保留很多旧会话文件的东西,比如改变了最大生命周期?或者你可能已经决定将它们存储在数据库中是一个好主意,但是忘了创建一个合适的索引?本机GC例程stat()用于检查到期的每个会话文件。如果构建了大量文件,这是非常耗时的。

edit: to help you for debugging only, disable garbage collection by temporarily setting session.gc-probability:

编辑:仅帮助您进行调试,通过临时设置session.gc-probability禁用垃圾收集:

session.gc-probability = 0

Make sure the settings stick, I don't know what the zend framework might be doing here.

确保设置坚持,我不知道zend框架可能在这里做什么。

P.S. It's difficult to suggestion a fix without knowing the cause. My answer is meant to guide you towards identifying the cause.

附:在不知道原因的情况下很难建议修复。我的回答是为了引导您找出原因。

#3


5  

I have had this problem and am surprised that nobody has posted this specific response. It may not be it but it is worth checking.

我遇到了这个问题,并且很惊讶没有人发布这个特定的回复。它可能不是它,但值得检查。

PHP LOCKS THE SESSION FILE while a page is processing, so that page can have exclusive access to it. Think about it, the sess_184c9aciqoc file is not a database, so two calls in the same session can't access it simultaneously. So if you have a lot of ajax calls, you can get a "traffic jam". Once you start doing advanced scripting this is a gotcha to beware of. by the way, here is a function to store an array of timestamps. I used this to figure out session start was the culprit:

PHP在页面处理时锁定会话文件,以便该页面可以对其进行独占访问。考虑一下,sess_184c9aciqoc文件不是数据库,因此同一会话中的两个调用不能同时访问它。因此,如果您有很多ajax呼叫,您可能会遇到“交通堵塞”。一旦你开始进行高级脚本编写,这是一个需要注意的问题。顺便说一句,这是一个存储时间戳数组的函数。我用这个来弄清楚会话开始是罪魁祸首:

//time function for benchmarking
if( function_exists('gmicrotime')){
    function gmicrotime($n=''){
        #version 1.1, 2007-05-09
        //store array of all calls
        global $mT;
        list($usec, $sec) = explode(' ',microtime());
        if(!isset($mT['_base_']))$mT['_base_']=$sec;
    $t=round((float)$usec + (float)(substr($sec,-4)),6);
    $mT['all'][]=$t;
    if($n){
        if(isset($mT['indexed'][$n])){
            //store repeated calls with same index.  If in a loop, add a $i if needed
            if(is_array($mT['indexed'][$n])){
                $mT['indexed'][$n][]=$t;
            }else{
                $mT['indexed'][$n]=array($mT['indexed'][$n],$t);
            }
        }else $mT['indexed'][$n]=$t;    
    }
    //return elapsed since last call (in the local array)
    $u=$mT['all'];
    if(count($u)>1){
        $mT['_total_']=$u[count($u)-1] - $u[0];
        return round(1000*($u[count($u)-1]-$u[count($u)-2]),6);
    }
}
gmicrotime('pageStart');
}

then i call as follows:

然后我打电话如下:

gmicrotime('beforeSessionStart');
session_start();
gmicrotime('afterSessionStart');

do_something_slow();
gmicrotime('afterSlowProcess');
//etc..
echo '<pre>';
print_r($mT);  

Hope this is helpful!

希望这有用!

#4


1  

Another approach might be that you have set a large memory_limit in PHP.ini.

另一种方法可能是您在PHP.ini中设置了一个大的memory_limit。

I did that for uploading huge mysql dumps into PHPMyAdmin and load time spiked, perhaps (as said above) a lot of session files piled up now that PHP had room to spare. The default is 128M, I think. I had quadrupled that.

我这样做是为了将巨大的mysql转储上传到PHPMyAdmin并加载加载时间,也许(如上所述)很多会话文件堆积起来,因为PHP有​​空间。我认为默认值是128M。我把它翻了四倍。

#5


0  

One way to avoid this problem is to ask PHP to store sessions in a database table instead of files.

避免此问题的一种方法是让PHP将会话存储在数据库表而不是文件中。

Firstly, I will give you a few links as real credits for this solution:

首先,我将为您提供一些链接作为此解决方案的真正信用:

http://www.tonymarston.net/php-mysql/session-handler.html

http://www.tonymarston.net/php-mysql/session-handler.html

http://shiflett.org/articles/storing-sessions-in-a-database

http://shiflett.org/articles/storing-sessions-in-a-database

http://culttt.com/2013/02/04/how-to-save-php-sessions-to-a-database/

http://culttt.com/2013/02/04/how-to-save-php-sessions-to-a-database/

Then a code implementation I derived from these readings:

然后我从这些读数中得到了一个代码实现:

<?php

class TLB_Sessions_in_Database
{
    private $debug;
    private $dbc;

    function __construct()
    {
        $this->debug = false;

        session_set_save_handler(
            array($this, '_open'),
            array($this, '_close'),
            array($this, '_read'),
            array($this, '_write'),
            array($this, '_destroy'),
            array($this, '_clean')
        );
    }

    function _open()
    {
        if( $this->debug ) echo '_open:'.PHP_EOL;

        if( ($this->dbc = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD)) !== false )
        {
            $select_db = mysql_select_db(DB_NAME, $this->dbc);
            $set_charset = mysql_set_charset(DB_CHARSET, $this->dbc);

            if( $this->debug ) echo '- return: '.(( $select_db && $set_charset ) ? 'true' : 'false').PHP_EOL;

            return( $select_db && $set_charset );
        }
        else
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( false );
    }

    function _close()
    {
        if( $this->debug ) echo '_close:'.PHP_EOL;

        return( mysql_close($this->dbc) );
    }

    function _read($session_id)
    {
        if( $this->debug ) echo '_read:'.PHP_EOL;

        $session_id = mysql_real_escape_string($session_id);

        $sql = "SELECT `session_data` FROM `".DB_NAME."`.`php_sessions` WHERE `session_id` = '".$session_id."'";

        if( $this->debug ) echo '- query: '.$sql.PHP_EOL;

        if( ($result = mysql_query($sql, $this->dbc)) !== false )
        {
            if( !in_array(mysql_num_rows($result), array(0, false), true) )
            {
                $record = mysql_fetch_assoc($result);

                return( $record['session_data'] );
            }
        }
        else
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( '' );
    }

    function _write($session_id, $session_data)
    {
        if( $this->debug ) echo '_write:'.PHP_EOL;

        $session_id = mysql_real_escape_string($session_id);
        $session_data = mysql_real_escape_string($session_data);

        //$sql = "REPLACE INTO `php_sessions` (`session_id`, `last_updated`, `session_data`) VALUES ('".$session_id."', '".time()."', '".$session_data."')";
        $sql = "INSERT INTO `".DB_NAME."`.`php_sessions` (`session_id`, `date_created`, `session_data`) VALUES ('".$session_id."', NOW(), '".$session_data."') ON DUPLICATE KEY UPDATE `last_updated` = NOW(), `session_data` = '".$session_data."'";

        if( ($result = mysql_query($sql, $this->dbc)) === false )
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( $result );
    }

    function _destroy($session_id)
    {
        if( $this->debug ) echo '_destroy:'.PHP_EOL;

        $session_id = mysql_real_escape_string($session_id);

        $sql = "DELETE FROM `".DB_NAME."`.`php_sessions` WHERE `session_id` = '".$session_id."'";

        if( ($result = mysql_query($sql, $this->dbc)) === false )
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( $result );
    }

    function _clean($max)
    {
        if( $this->debug ) echo '_clean:'.PHP_EOL;

        $sql = 'DELETE FROM `'.DB_NAME.'`.`php_sessions` WHERE `last_updated` < DATE_SUB(NOW(), INTERVAL '.$max.' SECOND)';

        if( ($result = mysql_query($sql, $this->dbc)) === false )
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( $result );
    }
}

new TLB_Sessions_in_Database();

END.

结束。

#6


0  

If you have multiple concurrent ajax calls on the same page this situation may cause your problem.

如果您在同一页面上有多个并发的ajax调用,则此情况可能会导致您的问题。

#7


0  

In my case it was incorrect memcache server settings in /etc/php.d/memcached.ini Here is information on memcache properties and here is how to setup storage in memcache.

在我的例子中,/ etc / php.d / memcached.ini中的memcache服务器设置不正确以下是有关memcache属性的信息,以及如何在memcache中设置存储。

#8


0  

I just had this issue. session_start was taking about 5sec.

我刚才有这个问题。 session_start大约需要5秒。

My issue was I had declared some variables above it.

我的问题是我在它上面声明了一些变量。

I moved session_start to the top and it now takes a few milliseconds.

我将session_start移到了顶部,现在需要几毫秒。

#1


18  

session_start (with sessions stored in files) is blocking in PHP, so this issue will appear if you try to start several server sessions for the same browser session (AJAX or multiple browser tabs/windows). Each session_start will wait until the other sessions have been closed.

session_start(会话存储在文件中)在PHP中是阻塞的,因此如果您尝试为同一浏览器会话(AJAX或多个浏览器选项卡/窗口)启动多个服务器会话,则会出现此问题。每个session_start将等待其他会话关闭。

See here: http://konrness.com/php5/how-to-prevent-blocking-php-requests/

见这里:http://konrness.com/php5/how-to-prevent-blocking-php-requests/

Try changing from files to database storage of sessions.

尝试从会话的文件更改为数据库存储。

#2


18  

My guess would be the garbage collection routine, which gets run inside of the native session_start() function. Maybe you've done something that keeps many old session files around, like changed the max life time? Or maybe you've decided it would be a good idea to store them in a database, but forgot to create a suitable index? The native GC routine stat()'s every single session file to check for expiration. This is time consuming if there's a lot of files built up.

我的猜测是垃圾收集例程,它在本机session_start()函数中运行。也许你做过一些可以保留很多旧会话文件的东西,比如改变了最大生命周期?或者你可能已经决定将它们存储在数据库中是一个好主意,但是忘了创建一个合适的索引?本机GC例程stat()用于检查到期的每个会话文件。如果构建了大量文件,这是非常耗时的。

edit: to help you for debugging only, disable garbage collection by temporarily setting session.gc-probability:

编辑:仅帮助您进行调试,通过临时设置session.gc-probability禁用垃圾收集:

session.gc-probability = 0

Make sure the settings stick, I don't know what the zend framework might be doing here.

确保设置坚持,我不知道zend框架可能在这里做什么。

P.S. It's difficult to suggestion a fix without knowing the cause. My answer is meant to guide you towards identifying the cause.

附:在不知道原因的情况下很难建议修复。我的回答是为了引导您找出原因。

#3


5  

I have had this problem and am surprised that nobody has posted this specific response. It may not be it but it is worth checking.

我遇到了这个问题,并且很惊讶没有人发布这个特定的回复。它可能不是它,但值得检查。

PHP LOCKS THE SESSION FILE while a page is processing, so that page can have exclusive access to it. Think about it, the sess_184c9aciqoc file is not a database, so two calls in the same session can't access it simultaneously. So if you have a lot of ajax calls, you can get a "traffic jam". Once you start doing advanced scripting this is a gotcha to beware of. by the way, here is a function to store an array of timestamps. I used this to figure out session start was the culprit:

PHP在页面处理时锁定会话文件,以便该页面可以对其进行独占访问。考虑一下,sess_184c9aciqoc文件不是数据库,因此同一会话中的两个调用不能同时访问它。因此,如果您有很多ajax呼叫,您可能会遇到“交通堵塞”。一旦你开始进行高级脚本编写,这是一个需要注意的问题。顺便说一句,这是一个存储时间戳数组的函数。我用这个来弄清楚会话开始是罪魁祸首:

//time function for benchmarking
if( function_exists('gmicrotime')){
    function gmicrotime($n=''){
        #version 1.1, 2007-05-09
        //store array of all calls
        global $mT;
        list($usec, $sec) = explode(' ',microtime());
        if(!isset($mT['_base_']))$mT['_base_']=$sec;
    $t=round((float)$usec + (float)(substr($sec,-4)),6);
    $mT['all'][]=$t;
    if($n){
        if(isset($mT['indexed'][$n])){
            //store repeated calls with same index.  If in a loop, add a $i if needed
            if(is_array($mT['indexed'][$n])){
                $mT['indexed'][$n][]=$t;
            }else{
                $mT['indexed'][$n]=array($mT['indexed'][$n],$t);
            }
        }else $mT['indexed'][$n]=$t;    
    }
    //return elapsed since last call (in the local array)
    $u=$mT['all'];
    if(count($u)>1){
        $mT['_total_']=$u[count($u)-1] - $u[0];
        return round(1000*($u[count($u)-1]-$u[count($u)-2]),6);
    }
}
gmicrotime('pageStart');
}

then i call as follows:

然后我打电话如下:

gmicrotime('beforeSessionStart');
session_start();
gmicrotime('afterSessionStart');

do_something_slow();
gmicrotime('afterSlowProcess');
//etc..
echo '<pre>';
print_r($mT);  

Hope this is helpful!

希望这有用!

#4


1  

Another approach might be that you have set a large memory_limit in PHP.ini.

另一种方法可能是您在PHP.ini中设置了一个大的memory_limit。

I did that for uploading huge mysql dumps into PHPMyAdmin and load time spiked, perhaps (as said above) a lot of session files piled up now that PHP had room to spare. The default is 128M, I think. I had quadrupled that.

我这样做是为了将巨大的mysql转储上传到PHPMyAdmin并加载加载时间,也许(如上所述)很多会话文件堆积起来,因为PHP有​​空间。我认为默认值是128M。我把它翻了四倍。

#5


0  

One way to avoid this problem is to ask PHP to store sessions in a database table instead of files.

避免此问题的一种方法是让PHP将会话存储在数据库表而不是文件中。

Firstly, I will give you a few links as real credits for this solution:

首先,我将为您提供一些链接作为此解决方案的真正信用:

http://www.tonymarston.net/php-mysql/session-handler.html

http://www.tonymarston.net/php-mysql/session-handler.html

http://shiflett.org/articles/storing-sessions-in-a-database

http://shiflett.org/articles/storing-sessions-in-a-database

http://culttt.com/2013/02/04/how-to-save-php-sessions-to-a-database/

http://culttt.com/2013/02/04/how-to-save-php-sessions-to-a-database/

Then a code implementation I derived from these readings:

然后我从这些读数中得到了一个代码实现:

<?php

class TLB_Sessions_in_Database
{
    private $debug;
    private $dbc;

    function __construct()
    {
        $this->debug = false;

        session_set_save_handler(
            array($this, '_open'),
            array($this, '_close'),
            array($this, '_read'),
            array($this, '_write'),
            array($this, '_destroy'),
            array($this, '_clean')
        );
    }

    function _open()
    {
        if( $this->debug ) echo '_open:'.PHP_EOL;

        if( ($this->dbc = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD)) !== false )
        {
            $select_db = mysql_select_db(DB_NAME, $this->dbc);
            $set_charset = mysql_set_charset(DB_CHARSET, $this->dbc);

            if( $this->debug ) echo '- return: '.(( $select_db && $set_charset ) ? 'true' : 'false').PHP_EOL;

            return( $select_db && $set_charset );
        }
        else
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( false );
    }

    function _close()
    {
        if( $this->debug ) echo '_close:'.PHP_EOL;

        return( mysql_close($this->dbc) );
    }

    function _read($session_id)
    {
        if( $this->debug ) echo '_read:'.PHP_EOL;

        $session_id = mysql_real_escape_string($session_id);

        $sql = "SELECT `session_data` FROM `".DB_NAME."`.`php_sessions` WHERE `session_id` = '".$session_id."'";

        if( $this->debug ) echo '- query: '.$sql.PHP_EOL;

        if( ($result = mysql_query($sql, $this->dbc)) !== false )
        {
            if( !in_array(mysql_num_rows($result), array(0, false), true) )
            {
                $record = mysql_fetch_assoc($result);

                return( $record['session_data'] );
            }
        }
        else
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( '' );
    }

    function _write($session_id, $session_data)
    {
        if( $this->debug ) echo '_write:'.PHP_EOL;

        $session_id = mysql_real_escape_string($session_id);
        $session_data = mysql_real_escape_string($session_data);

        //$sql = "REPLACE INTO `php_sessions` (`session_id`, `last_updated`, `session_data`) VALUES ('".$session_id."', '".time()."', '".$session_data."')";
        $sql = "INSERT INTO `".DB_NAME."`.`php_sessions` (`session_id`, `date_created`, `session_data`) VALUES ('".$session_id."', NOW(), '".$session_data."') ON DUPLICATE KEY UPDATE `last_updated` = NOW(), `session_data` = '".$session_data."'";

        if( ($result = mysql_query($sql, $this->dbc)) === false )
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( $result );
    }

    function _destroy($session_id)
    {
        if( $this->debug ) echo '_destroy:'.PHP_EOL;

        $session_id = mysql_real_escape_string($session_id);

        $sql = "DELETE FROM `".DB_NAME."`.`php_sessions` WHERE `session_id` = '".$session_id."'";

        if( ($result = mysql_query($sql, $this->dbc)) === false )
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( $result );
    }

    function _clean($max)
    {
        if( $this->debug ) echo '_clean:'.PHP_EOL;

        $sql = 'DELETE FROM `'.DB_NAME.'`.`php_sessions` WHERE `last_updated` < DATE_SUB(NOW(), INTERVAL '.$max.' SECOND)';

        if( ($result = mysql_query($sql, $this->dbc)) === false )
        {
            if( $this->debug ) echo '- error: '.mysql_error($this->dbc).PHP_EOL;
        }

        return( $result );
    }
}

new TLB_Sessions_in_Database();

END.

结束。

#6


0  

If you have multiple concurrent ajax calls on the same page this situation may cause your problem.

如果您在同一页面上有多个并发的ajax调用,则此情况可能会导致您的问题。

#7


0  

In my case it was incorrect memcache server settings in /etc/php.d/memcached.ini Here is information on memcache properties and here is how to setup storage in memcache.

在我的例子中,/ etc / php.d / memcached.ini中的memcache服务器设置不正确以下是有关memcache属性的信息,以及如何在memcache中设置存储。

#8


0  

I just had this issue. session_start was taking about 5sec.

我刚才有这个问题。 session_start大约需要5秒。

My issue was I had declared some variables above it.

我的问题是我在它上面声明了一些变量。

I moved session_start to the top and it now takes a few milliseconds.

我将session_start移到了顶部,现在需要几毫秒。