2012-11-26 17 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

分享它尝试后的方式 –