如何使用ESI构建Symfony2应用程序?

时间:2012-11-26 23:11:28

标签: caching symfony varnish 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或Varnish)上。地点列表也将在网关上大部分时间缓存。用户数据请求将是被调用但不被缓存的用户数据(至少最初不是)。

问题

  1. 你觉得这个结构怎么样?
  2. 如果用户是匿名用户,我可以避免为用户数据制作esi-includes吗?如果我有anon用户的cookie?怎么样?
  3. 用户菜单的esi-include是否有意义?
  4. 或者我们应该忘记ESI并始终通过控制器(例如缓存常见数据的渲染视图)?
  5. 我们应该将要求用户数据的2个ESI请求移动到AJAX调用,而不是在服务器上等待吗?
  6. 如果我们需要快速做到这一点,这是一个很好的扩展方法吗?什么是最好的?
  7. 非常感谢!

1 个答案:

答案 0 :(得分:5)

我们在一个网站上使用Varnish进行整页缓存,并且我已经使用Symfony2几年了,但请记住,我没有在任何生产环境中使用Varnish + Symfony2 + ESI。

  1. 我认为基本的想法是可以的。如果许多页面中的菜单相同,并且许多页面上的位置列表也相同,则会获得Varnish或Symfony反向缓存缓存的常用内容。由于Varnish通常在内存中保存缓存,因此您可以更快地获取内容,而无需在每次请求时调用呈现和数据库查询代码。

    如果用户已登录,那么困难的部分就是将这些ESI请求缓存。据我所知,在默认的Varnish配置中,其中包含Cookie的请求永远不会被缓存。如果您倾向于将cookie传递给ESI请求,则不会在用户之间共享这些ESI响应。

    您可以尝试从URL制定一些规则,但如果您使用默认的Symfony twig帮助程序,生成的URL是/ _internal / ...,因此可能很难区分公共和私有。

    此外,您可以配置为在传递Cache-Control: public时始终忽略任何Cookie。默认情况下,这在Symfony中完成:

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

    正如您从代码中看到的那样,如果您有public指令,则响应永远不会是私有的。

    我还没有找到Varnish如何处理这个指令 - 据我所知,它没有默认缓存任何有cookie的请求。所以我认为你必须调整配置来实现这一目标。

  2. 如果还要缓存主页面,我看不到你如何跳过包含。

    我认为您的注册用户(不是搜索机器人)需要JS,所以我建议使用Javascript来区分用户数据的加载。

    如果用户有cookie session-id等,则可以查看Javascript代码,并仅在此情况下请求获取数据。设置其他cookie(例如_loggedin)以避免Javascript代码获取会话ID也可能是个好主意。

    未登录用户也可以在Cookie中包含一些数据,例如_likedPost:1,2,132。 Javascript可以获取此cookie并进行一些HTML更正,甚至不需要额外的请求。

    正如我们对这些cookie所做的那样:我们将仅限JS的cookie与应用程序cookie分开。我们通过某种模式实现了这一点,例如JS _\w。然后我们调整了Varnish配置以拆分Cookie标头并删除这些仅限JS的cookie。然后,如果没有其他cookie,则与每个人共享响应。应用程序(Symfony)不会获取这些cookie,因为它们被剥离了。

  3. 我认为如果每页都相同,我会这样做。

  4. 我认为ESI很好,因为Varnish可以在内存中保存缓存。因此,它可能甚至不会对您的硬盘进行任何查询。由于您的控制器缓存可能也在内存中,我认为Varnish会比Symfony框架更快地查找缓存,包括所有路由,PHP代码,服务初始化等。

  5. 这取决于,但我认为这可能是更好的方法。请记住,缓存过着不同的生活。例如,如果您的地点列表缓存了2个小时,则在此时间结束时,地点可能已更改 - 某些新项目在列表中是新项目,其中一些项目缺失。您的用户列表仍然是旧的(缓存),但您提供有关新列表的用户数据 - 不需要某些数据,其中一些数据丢失。

    通过javascript获取加载位置可能是更好的方法,例如搜索某些HTML属性,如data-list-item-id,然后发出ajax请求查询有关这些项的数据。在这种情况下,您的用户数据将与当前缓存列表同步,您可以为两个列表而不是2列出1 ajax请求。

  6. 如果未使用缓存失效(PURGE请求),则所有HTTP缓存都可以很好地扩展。您可以将应用程序扩展到多个服务器,并按照某种规则配置Varnish随机调用它们,或者只使用其中一个作为故障保护。如果带宽仍然太大,您可以随时修改缓存超时和其他配置。