简体   繁体   English

session_start() 需要很长时间

[英]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.它基于 Zend Application,我曾经制作过大约几十个这样的网站,所以我确信我的代码是没问题的。

I installed xdebugger on server, tried to profile it and guess what?我在服务器上安装了 xdebugger,试图对其进行分析并猜猜是什么? php::session_start() took 48.675 seconds. php::session_start() 耗时 48.675 秒。 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). session_start (会话存储在文件中)在 PHP 中被阻塞,因此如果您尝试为同一个浏览器会话(AJAX 或多个浏览器选项卡/窗口)启动多个服务器会话,则会出现此问题。 Each session_start will wait until the other sessions have been closed.每个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.尝试从文件更改为会话的数据库存储。

My guess would be the garbage collection routine, which gets run inside of the native session_start() function.我的猜测是垃圾收集例程,它在本机session_start()函数内部运行。 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.本机 GC 例程 stat() 会检查每个会话文件是否过期。 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禁用垃圾收集:

session.gc-probability = 0

Make sure the settings stick, I don't know what the zend framework might be doing here.确保设置保持不变,我不知道 zend 框架可能在这里做什么。

PS It's difficult to suggestion a fix without knowing the cause. PS 在不知道原因的情况下很难提出修复建议。 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. PHP 在处理页面时锁定会话文件,以便该页面可以独占访问它。 Think about it, the sess_184c9aciqoc file is not a database, so two calls in the same session can't access it simultaneously.想想看,sess_184c9aciqoc文件不是数据库,所以同一个会话中的两个调用是不能同时访问的。 So if you have a lot of ajax calls, you can get a "traffic jam".所以如果你有很多ajax调用,你就会遇到“堵车”。 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.另一种方法可能是您在 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.我这样做是为了将巨大的 mysql 转储上传到 PHPMyAdmin 并且加载时间激增,也许(如上所述)由于 PHP 有空闲空间而堆积了很多会话文件。 The default is 128M , I think.我想默认是128M I had quadrupled that.我已经翻了四倍。

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.结尾。

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

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

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

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.我的页面在许多 <img src="download_image.php"> 标签中打开并发会话,其中 download_image.php 运行 session_start() 然后下载图像。

Inserting a session_write_close() in download_image.php fixed my problem.在 download_image.php 中插入 session_write_close() 解决了我的问题。

session_start();

session_write_close(); 

download_image();

I have tried memcached and session_start(['read_and_close'=>true]).我试过 memcached 和 session_start(['read_and_close'=>true])。 But only session_write_close() works for me.但只有 session_write_close() 对我有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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