2012-12-07 141 views
20

Mys网站的工作速度非常缓慢(我对此没有任何想法)。它基于Zend Application,我曾经制作过大约几十个这样的网站,所以我确信我的代码是可以的。session_start()需要很长的时间

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

xdebugger profiling results

+1

48秒开始会话?这是疯了!会话中有多少数据?你使用任何会话处理库吗?将会话保存到不寻常的位置?数据库(检查你的索引)?非本地文件系统?它运行什么类型的服务器?你有没有在php.ini或.htaccess中的任何会话配置? – Spudley

回答

18

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

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

session.gc-probability = 0 

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

P.S.在不知道原因的情况下很难提出修复建议。我的答案旨在引导您找出原因。

17

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

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

尝试从文件转变为会议的数据库存储。

+0

谢谢,就是这样。 [session_write_close](http://php.net/manual/en/function.session-write-close.php)帮助了我。 – Curious

+0

谢谢,与长池相同的问题,所以如果一个脚本正在等待,session_write_close在等待/睡眠之前,并且在唤醒之后再次session_start。 – KyleK

1

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

我这样做是为了将大量的MySQL转储上传到PHPMyAdmin并加载时间尖峰,或许(如上所述)大量的会话文件堆积起来,PHP有空余空间。我想,默认值是128M。我已经翻了两番。

4

我有这个问题,并且很惊讶没有人发布这个特定的响应。它可能不是这样,但它值得检查。

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'); 
} 

然后调用如下:

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

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

希望这是有帮助的!

0

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

首先,我会给你几个环节,作为该解决方案真正的学分:

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/

然后,代码实现,我从这些读数得出:

<?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。

0

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

0

在我的情况下,它在/etc/php.d/memcached.ini Here是不正确的内存缓存服务器设置是在内存缓存性能和here信息是如何设置内存缓存中存储。

+0

这是个不好的答案,因为它没有告诉错误或正确的设置。 –

+0

@kikosoftware memcached设置可能因您尝试实现的内容而异。你可以在这里了解更多[这里](http://php.net/manual/en/memcached.configuration.php)。在我的情况''扩展'设置缺少指向弹性库。 请求您删除downvote – vikramaditya234

+0

感谢您添加该信息。在链接到的PHP手册页上没有看到“扩展”设置。你的意思是'memcached.serializer'吗?目前,我无法删除我的downvote:“你昨天最后投票回答了这个问题,你的投票现在被锁定,除非这个答案被编辑了。”这很有道理。 –

0

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

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

我将session_start移至顶端,现在需要几毫秒。