简体   繁体   中英

session_start() takes VERY LONG TIME

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.

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 分析结果

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.

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

Try changing from files to database storage of sessions.

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.

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

session.gc-probability = 0

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

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

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:

//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!

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

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.

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

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

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

http://shiflett.org/articles/storing-sessions-in-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.

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

就我而言,它是/etc/php.d/memcached.ini memcache 服务器设置不正确这里是有关 memcache 属性的信息, 这里是如何在 memcache 中设置存储。

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

My issue was I had declared some variables above it.

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

My page opens concurrent sessions within many <img src="download_image.php"> tags where download_image.php run session_start() and then downloading the image.

Inserting a session_write_close() in download_image.php fixed my problem.

session_start();

session_write_close(); 

download_image();

I have tried memcached and session_start(['read_and_close'=>true]). But only session_write_close() works for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM