php session_start() 需要很长时间

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13772074/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 06:02:37  来源:igfitidea点击:

session_start() takes VERY LONG TIME

phpperformancezend-frameworksessionprofiling

提问by ABTOMAT

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.

我的网站运行非常缓慢(我不知道为什么)。它基于 Zend Application,我曾经制作过大约几十个这样的网站,所以我确信我的代码是没问题的。

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 秒。四十八秒半!这太不可思议了!这可能是什么原因?很普通的操作,怎么会执行这么久?如何解决这种行为,要编辑哪些配置?通过谷歌搜索,但没有找到好的答案(几乎到处都有问题,但没有答案)。先谢过!

xdebugger profiling results

xdebugger 分析结果

回答by goat

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.

PS 在不知道原因的情况下很难提出修复建议。我的回答旨在指导您确定原因。

回答by Christian Davén

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_startwill 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.

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

回答by Samuel Fullman

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!

希望这是有帮助的!

回答by PeerBr

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

另一种方法可能是您memory_limit在 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.

我这样做是为了将巨大的 mysql 转储上传到 PHPMyAdmin 并且加载时间激增,也许(如上所述)由于 PHP 有空闲空间而堆积了很多会话文件。默认是128M,我想。我已经翻了四倍。

回答by Tristan CHARBONNIER

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.

结尾。

回答by Nicolas Finelli

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

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

回答by vikramaditya234

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

在我的情况下,它是不正确的内存缓存服务器设置/etc/php.d/memcached.ini这里是有关内存缓存属性的信息,这里是如何在内存缓存中设置存储。

回答by Shane Zammit

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 移到顶部,现在需要几毫秒。