背景
公司的外網線上專案連續當機將近2周時間,後來通過查詢日誌,發現是某度蜘蛛大量爬取造成。因為公司花錢進行了SEO推廣,所以也不能直接禁掉蜘蛛,所以一度造成網站打不開的情況。期間增加頻寬,擴容cpu,增強搜尋引擎叢集等方案,都得不到好的效果。
分析
開始優化程式碼,記錄慢日誌,在雲平臺看慢查詢,漸漸優化慢查詢,但是問題依舊。慢慢通過分析慢日誌注意到如下細節:
這裡我摘取了兩個日誌片段,其實類似日誌片段還有非常多。可以看到將近相同的時間不同的許多程式都進行了GC,而這裡的所謂GC是什麼?
在StartSession.php上看到了如下程式碼:
/**
* Remove the garbage from the session if necessary.
*
* @param \Illuminate\Session\SessionInterface $session
* @return void
*/
protected function collectGarbage(SessionInterface $session)
{
$config = $this->manager->getSessionConfig();
// Here we will see if this request hits the garbage collection lottery by hitting
// the odds needed to perform garbage collection on any given request. If we do
// hit it, we'll call this handler to let it delete all the expired sessions.
if ($this->configHitsLottery($config)) {
$session->getHandler()->gc($this->getSessionLifetimeInSeconds());
}
}
這裡註釋的意思是有一定概率進行GC,並不是每次都進行GC,先來看下GC做了什麼事情。
因為配置的是檔案session,所以我們找到檔案Session的實現檔案FileSessionHandler.php,摘取GC函式程式碼如下:
/**
* {@inheritdoc}
*/
public function gc($lifetime)
{
$files = Finder::create()
->in($this->path)
->files()
->ignoreDotFiles(true)
->date('<= now - '.$lifetime.' seconds');
foreach ($files as $file) {
$this->files->delete($file->getRealPath());
}
}
程式碼的意思很簡單,就是通過搜尋檔案,獲取到過期的session檔案然後進行刪除,這裡的過期時間在session.php的配置裡定義:
/*
|--------------------------------------------------------------------------
| Session Lifetime
|--------------------------------------------------------------------------
|
| Here you may specify the number of minutes that you wish the session
| to be allowed to remain idle before it expires. If you want them
| to immediately expire on the browser closing, set that option.
|
*/
'lifetime' => 120,
'expire_on_close' => true,
可以看到預設是2個小時,下面一個引數的意義是是否要在瀏覽器關閉的時候立即過期!剛才說到了,有一定概率執行這個GC,那這個概率多大呢?
/**
* Determine if the configuration odds hit the lottery.
*
* @param array $config
* @return bool
*/
protected function configHitsLottery(array $config)
{
return random_int(1, 100) <= 2;
}
上面程式碼是我把預設配置替換後的結果,也就是會有2%的可能會觸發一次GC!而一次GC我們要回收兩個小時之前的過期session檔案。如果在併發量稍微有點大的情況下,要刪除的檔案其實是非常可觀的,刪除這個IO操作就是直接導致了cpu負荷直接超載的罪魁禍首。
解決方案
方法很簡單,就是換driver,比如集中式的redis session方案。
總結
雖然這次專案的主要負責人不是我,不過通過這次抓取日誌,跟蹤程式碼,分析程式碼學到了很多優化的一手資料。Laravel其實是一個相當靈活的框架,檔案session方式只能在測試環境進行應用,而線上上環境必須上集中式session方式,不然流量起來的時候,就會吃苦頭。Laravel如不經過優化的情況下,他的效能是不高的,好在他也提供了很多可以優化的擴充套件介面,算的上是目前PHP裡相當成熟的框架了。
本作品採用《CC 協議》,轉載必須註明作者和本文連結