在一个拥有大量流量的新项目中,我们正在考虑如何构建我们的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)上。地点列表也将在网关上大部分时间缓存。用户数据请求将是被调用但不被缓存的用户数据(至少最初不是)。
问题:
非常感谢!
答案 0 :(得分:5)
我们在一个网站上使用Varnish进行整页缓存,并且我已经使用Symfony2几年了,但请记住,我没有在任何生产环境中使用Varnish + Symfony2 + ESI。
我认为基本的想法是可以的。如果许多页面中的菜单相同,并且许多页面上的位置列表也相同,则会获得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的请求。所以我认为你必须调整配置来实现这一目标。
如果还要缓存主页面,我看不到你如何跳过包含。
我认为您的注册用户(不是搜索机器人)需要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,因为它们被剥离了。
我认为如果每页都相同,我会这样做。
我认为ESI很好,因为Varnish可以在内存中保存缓存。因此,它可能甚至不会对您的硬盘进行任何查询。由于您的控制器缓存可能也在内存中,我认为Varnish会比Symfony框架更快地查找缓存,包括所有路由,PHP代码,服务初始化等。
这取决于,但我认为这可能是更好的方法。请记住,缓存过着不同的生活。例如,如果您的地点列表缓存了2个小时,则在此时间结束时,地点可能已更改 - 某些新项目在列表中是新项目,其中一些项目缺失。您的用户列表仍然是旧的(缓存),但您提供有关新列表的用户数据 - 不需要某些数据,其中一些数据丢失。
通过javascript获取加载位置可能是更好的方法,例如搜索某些HTML属性,如data-list-item-id
,然后发出ajax请求查询有关这些项的数据。在这种情况下,您的用户数据将与当前缓存列表同步,您可以为两个列表而不是2列出1 ajax请求。
如果未使用缓存失效(PURGE请求),则所有HTTP缓存都可以很好地扩展。您可以将应用程序扩展到多个服务器,并按照某种规则配置Varnish随机调用它们,或者只使用其中一个作为故障保护。如果带宽仍然太大,您可以随时修改缓存超时和其他配置。