2012-11-26 53 views
19

在一個擁有大量流量的新項目中,我們正在考慮如何構建我們的Symfony2應用程序以充分利用緩存,並準備在未來更具侵略性。我很想知道你的意見。如何使用ESI構建Symfony2應用程序?

比方說,用戶請求一個頁面的地方列表。這個頁面有:

- list 
    - common data (title, author, description) 
    - user data (the user likes the list + other data) 
- first 20 places 
    - common data (title, photo of each place) 
    - user data (the rates of the user for those places) 

的HTML可能是這樣的:

<html>... 
<body> 
    <header> 
    ... 
    <!-- Embed the top user menu --> 
    <esi:include src="http://example.com/profile/menu" /> 
    ... 
    </header> 

    <content> 
    ... 
    common data of the list 
    ... 
    <!-- Embed the common data of the first 20 places, the same for everyone --> 
    <esi:include src="http://example.com/lists/17/places" /> 
    ... 
    <!-- Embed the user data of the list (used in JS) --> 
    <esi:include src="http://example.com/lists/17/user" /> 
    ... 
    <!-- Embed the user data of the list of places (used in JS) --> 
    <esi:include src="http://example.com/lists/17/places/user" /> 
    ... 
    </content> 
</body>  
</html> 

的HTML將在網關(Symfony的或清漆)進行緩存。大部分時間都會在網關上緩存地點列表。用戶數據請求將被調用並且不被緩存(至少不是最初)。

問題

  1. 你怎麼看待這種結構?
  2. 如果用戶是匿名的,我可以避免爲用戶數據製作esi-includes嗎?另外,如果我有一個匿名用戶的cookie?怎麼樣?
  3. 用戶菜單的esi-include是否有意義?
  4. 或者我們應該忘記ESI並始終通過控制器(例如緩存公共數據的渲染視圖)?
  5. 我們應該將請求用戶數據的2個ESI請求移動到AJAX調用,而不是在服務器上等待嗎?
  6. 如果我們需要快速完成這是一個很好的縮放方法嗎?什麼是最好的?

非常感謝!

回答

4

我們在一個站點上使用了Varnish進行整頁緩存,我已經使用了Symfony2幾年了,但請記住,我沒有在任何生產環境中使用Varnish + Symfony2 + ESI。

  1. 我覺得基本的想法是可以的。如果菜單在許多頁面中相同,並且在許多頁面上的位置列表也相同,則會獲得由Varnish或Symfony反向緩存緩存的常用內容。由於Varnish通常在內存中保存緩存,因此您可以更快速地獲取內容,而無需在每次請求時調用渲染和數據庫查詢代碼。

    困難的部分是讓這些ESI請求緩存,如果用戶登錄。據我所知,在默認的Varnish配置中,Cookie中的請求不會被緩存。如果您傾向於將Cookie傳遞給ESI請求,那麼這些ESI響應將不會在用戶之間共享。

    您可以嘗試從URL製作一些規則,但如果您使用默認的Symfony樹枝助手,則生成的網址爲/ _internal/...,因此可能很難區分公共和私有網站。

    如果通過Cache-Control: public,您也可以配置爲始終忽略任何cookie。這是通過默認的Symfony完成:

    if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) { 
        $response->setPrivate(true); 
    } 
    

    正如你從代碼中看到,如果你有public指令,反應永遠是私有的。

    我還沒有找到Varnish如何處理這個指令 - 據我所知,它不會緩存任何有默認cookie的請求。所以我認爲你必須調整配置來完成這個。

  2. 如果主頁面也被緩存,我看不到如何跳過包含。

    我假設你的註冊用戶(不是搜索機器人)需要JS,所以我建議使用Javascript來區分用戶數據的加載。

    Javascript代碼可以看看用戶是否有cookie session-id等,並請求僅在這種情況下獲取數據。設置其他一些cookie也是一個好主意,例如_loggedin以避免Javascript代碼獲取會話ID。

    未登錄用戶也可以在Cookie中有一些數據,如_likedPost:1,2,132。 Javascript可以得到這個cookie,並做一些HTML更正,甚至沒有提出額外的請求。

    正如我們對這些cookies做的那樣:我們從應用程序cookie中分離出僅限JS的cookie。我們通過某種模式完成了這項工作,如JS Cookie的_\w。然後,我們調整了Varnish配置來分割Cookie標頭並刪除這些僅限JS的Cookie。然後,如果沒有其他cookie,剩下的響應就會與所有人分享。應用程序(Symfony)不會獲取這些cookie,因爲它們被剝離。

  3. 我想如果它在每一頁都是一樣的。

  4. 我認爲ESI是好的,因爲清漆可以在內存中保存緩存。因此,它可能甚至不會對您的硬盤進行內容查詢。由於您的控制器緩存也可能在內存中,因此我認爲Varnish會比Symfony框架更快地尋找所有路由,PHP代碼,服務初始化等。

  5. 這取決於,但我認爲它可以是更好的方法。請記住,這些緩存過着不同的生活。例如,如果您的地點列表被緩存了2個小時,在這段時間結束時,地點可能發生了變化 - 列表中的一些新項目是新的,並且其中一些項目丟失。您的用戶列表仍然是舊的(緩存),但是您提供了有關新列表的用戶數據 - 其中一些數據不是必需的,有些數據缺失。

    這可能是更好的方法來獲取JavaScript的加載位置,例如搜索一些HTML屬性,如data-list-item-id,然後使ajax請求查詢有關這些項目的數據。在這種情況下,您的用戶數據將與當前緩存列表同步,並且您可以對兩個列表而不是2進行同步請求。

  6. 如果不使用緩存失效(PURGE請求),則所有HTTP緩存時間確實很好進行縮放。您可以將應用程序擴展到多個服務器,並配置Varnish根據某些規則隨機調用它們,或者僅將其中一個用作故障安全。如果帶寬仍然過大,您可以隨時修改緩存超時和其他配置。

+0

非常感謝barius, 我們正在代替ESI Ajax中的用戶數據請求。所以我同意你的看法。讓我們看看它是如何發展的。 關鍵&樂趣部分將與避免使用PURGE。這是能夠擴展的目標。 – fesja

+0

分享它嘗試後的方式 –