2014-01-10 31 views
4

我們有一個高流量的網站,很像StackOverflow和memcache中的對象緩存。該網站使用PHP(CodeIgniter)和MySQL構建。如何防止緩存過期時數據庫被應用程序DDOSed?

每次TTL(生存時間)在作爲每個頁面加載的一部分的緩存對象上過期時,此時加載的所有頁面都會導致對數據庫的查詢,從而有效地對數據庫執行DDOS。

是否有某種方式只有一個頁面載入重新獲取數據,並讓其他頁面加載等待緩存被第一個更新?

我的第一個想法是讓一個隨機數發生器工作,讓一些頁面加載獲取數據,並讓其他人在重新檢查緩存之前等待一秒鐘。但一定有更好的辦法。

+0

+1用於緩存考慮!然而,它會導致多個額外的查詢,因爲您將讓其他請求輪詢數據庫,直到您將頁面標記爲「重新放入緩存」 –

+1

請參閱[避免踩踏牧羣](https://code.google.com/p/memcached /維基/ NewProgrammingTricks#Avoiding_stampeding_herd)。 – eggyal

+0

@eggyal很多有趣的想法,謝謝。 – jorisw

回答

2

你可以用我的算法從這個代碼:https://github.com/jamm/Memory/blob/master/lib/Jamm/Memory/MemcacheObject.php#L230

  1. 讀取鍵和TTL
  2. 如果TTL小(小於5秒, 爲例),試圖鎖定特殊鍵(不是您正在閱讀),像
  3. 如果鎖定成功「_Update {} name_of_key」 - 計算(或 讀)新的價值,並刷新緩存
  4. 版本更新密鑰。

所以只有1個進程會從數據庫讀取新值。

+0

謝謝。緩存鎖定的概念對我來說是新的。我會看看我是否可以將該解決方案應用到我們的應用程序中 – jorisw

2

如果您可以控制後臺任務(如cronjobs),則可以安排完成工作並在所需時間之前提取數據,以便最新數據永遠不會超出緩存。

例如,您可以每20分鐘(或每分鐘處理一次)運行一次作業,更新緩存的值。在該作業運行時,不需要其他數據庫查詢來獲取數據。

+0

這是一個好主意。我們已經這樣做了,對於頁面加載時間總是需要太長時間才能接受的請求而言,實際上已經這樣做。事實上,我可以讓一個cronjob定期檢查每個緩存項目的TTL並在前幾秒刷新它們。 – jorisw

1

,爲明確我的答案我會寫一些代碼來說明我的彪(這可能是一個解決方案的所有反正後...):

if ($this->cacheExpired()){ 
    if (!$this->isMarkedAsRegenerating()) 
    { 
     $this->markAsRegenerating();    //..ing 
     $this->regenerateCache(); 
     $this->markAsCacheRegenerated();   //..ed 
    } else { 
     while ($this->isMarkedAsRegenerating()) 
     { 
       sleep(1); //sleep 1 second to decrease database-queries, we are preventing a DDOS you know... 
     } 
    } 
} 

$this->output(); //at this point, we always have a cached version of the page 

參與唯一的風險是在兩個網頁點擊量非常相同的時間*會使緩存重新生成兩次成爲可能。這是非常不可能的,但如果它發生至少所有其他請求仍在等待。

+0

謝謝,如果我理解正確的話,這與其他人稱之爲緩存鎖定的基本相同。 – jorisw

相關問題