2012-12-07 113 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移至頂端,現在需要幾毫秒。