按新鲜度细分
2008年6月24日
媒体网站面临的最大问题之一是处理大量流量。媒体的本质是吸引眼球,但如果一次性收到太多访问,缓慢的性能会导致问题并损害你的声誉。这种问题因这种网络流量的突发性而加剧。你可能以可控的速度平稳运行,然后突然出现一条重大新闻,导致流量激增。我们的一位客户在短短几分钟内就经历了流量增长了两个数量级。
在计算领域,加快对相同信息的访问的通用解决方案是使用缓存。如果你不断请求我的主页,Web 服务器会在内存中建立一个缓存,这样重复的请求就可以避免访问磁盘。
为我的网站保留缓存很容易,因为这个页面,就像我的整个网站一样,完全是静态的。然而,大多数媒体网站包含大量动态内容。你可能认为普通的报纸网站上没有多少业务逻辑,但一旦你开始关注广告链接、相关故事、特色内容等等,事情就会变得有趣得多。一篇关于法国旅行的文章可能会链接到关于法国美食的文章,以及知道加拿大浏览器对卢瓦尔河谷度假感兴趣的广告。个性化会让情况更糟,我的个性化偏好应该在我的重型红酒列表上生成个性化功能列表。这种逻辑本身就很复杂,它会为每个请求带来大量计算,最重要的是,它会破坏大多数缓存策略。
解决这个问题的方法是将页面分成多个段,每个段都有类似的新鲜度确定。关于卢瓦尔旅行的文章可以相对静态,只更改以纠正错误。一个从“法国”和“卢瓦尔”标签中获取信息的相关文章列表会更频繁地更改,但可能每隔几天才会更改一次。如果我们正确地安排好,请求包含这两个项目的页面就可以从缓存中获取所有内容。
我见过的最常见的方法是在 Web 服务器上形成缓存,并在页面被访问时组装页面段。像 Sitemesh 这样的工具是这种方法的一个不错的选择。当你为 18 世纪卢瓦尔河的美味佳肴编写页面时,你包含了对相关文章等部分的调用。当你收到实际的 Web 请求时,Web 服务器会获取页面并从各个部分组装页面。其中大部分可以在 Web 服务器中缓存,从而避免访问后端域逻辑和数据库。
一个有趣的可能性是更进一步,利用 Web 本身存在的众多缓存。大多数对这个 Web 页面的调用甚至不会到达我的 Web 服务器,因为我的页面在传输过程中被多次缓存。如果你动态地构建一个 Web 页面并在服务器上组装它,你必须承担交付页面的损失。另一种方法是在客户端组装页面,然后从其自己的 URL 中提取每个段。每个段可以在不同的地方以不同的缓存策略进行缓存。
这将如何运作?我们可以将静态文章内容存储为 XHTML,其 URL 为 http://gallifreyTimes/travel/18-century-loire-delights
。在该文件中,我们希望通过查找标记为“卢瓦尔”和“法国”的文章来插入一些相关文章。在静态页面中,我们放置一个简单的“a”标签。
<a class = "relatedLinks" href = "relatedLinks/france+loire">Related Links</a>
在静态页面的标题中,我们将其链接到一个单独的库文件中的某些 JavaScript。当我们下载卢瓦尔文章时,JavaScript 会运行并扫描文章以查找具有正确类的元素:在本例中,是具有“relatedLinks”类的“a”元素。(行为库 是一个很好的方法。)当它找到该元素时,它会使用该元素中的信息来合成该段的 URL。在本例中,它将使用元素的 href 属性中的内容来生成一个类似于 http://gallifreyTimes/relatedArticles/france+loire
的 URL。一旦它获得了该 URL,它就会获取内容并使用它来替换原始的“a”元素。由于相关文章列表是通过 URL 处理的,因此对该 URL 的其他获取会导致 Internet 中的缓存预热,因此很有可能检索页面永远不会导致对原始服务器的访问。
这种使用 JavaScript 替换占位符元素以获取更多内容的技术是 渐进增强 的一种形式。我发现的关于渐进增强的描述侧重于为具有有限浏览器的可访问性添加功能。这个例子也有这个好处。如果我使用没有 JavaScript 的浏览器浏览页面,我会得到一个有用的链接。渐进增强背后的总体思路是,提供的基本页面在基本浏览器上是有用的,然后我们使用 JavaScript 等技术来添加更多花哨的功能。
在缓存的上下文中,其价值在于每个渐进增强都将一个具有不同新鲜度规则的 HTML 块编织在一起。原始页面是静态的,相关链接每天都会更改,但两者都可以独立缓存并编织在一起。我可以做各种额外的元素,只要我注意根据新鲜度规则对页面进行分段。因此,我可以通过让 JavaScript 从 HTTP 会话中获取用户 ID,使用它来构建类似于 http://gallifreyTimes/personalWeather/martinfowler
的 URL,检索内容(通常会缓存在我的硬盘驱动器上)并将它编织到页面中,从而在每个页面中包含一个基于用户个人资料的个性化天气预报。