从购买牛奶谈到Web缓存(译)

1,426 阅读9分钟
  • 此文章为中文译文,有不足或者错误之处,敬请指正。原文传送门:点击这里

如果你曾在商场买过牛奶,那么你将会很好地理解服务端及浏览器端的缓存机制。

如果你是一个忠实的因特网用户,你时时刻刻都在享受缓存所带来的好处。但是,你可能并不清楚它是在何时,以何种方式施展它的“魔法”。

从一个开发者的角度来说,缓存机制使得创建一个高性能web应用或者web服务器变得更为容易。开发者通过运用缓存协议,就不必频繁地去优化服务器以应对大量请求而可能导致的服务器崩溃。

虽说缓存带来的可能只是加载页面时,两秒变成一秒的差异,这种影响看上去似乎有一点...可有可无。但是,如果你的站点想要支持大量用户使用,那么这点变化是必要的。

在之前的web应用中使用了缓存策略以后,我意识到可以用一些更为合适的方式去解释缓存机制,而不仅仅是通过一大堆术语。我注意到这个过程和牛奶从农场到你家冰箱这段路程很类似,所以我觉得这是一个不错的解释方式。

为了更好的理解本篇文章,你需要了解一下一些web服务器的一些基本概念。现在我们开始吧!

没有缓存机制,互联网会是什么样?

在我们深入了解缓存之前,我们先来思考一下没有缓存的话,互联网会是什么样?想象一下,假如你生活在18世纪至19世纪的某一个农村。你拥有一个农场,那时并没有可用的冷藏设备。你的农场饲养了几头奶牛,但是它们产的牛奶并没有想象的有价值,因为很快牛奶就会变质。

让我们把思绪拉回,即便是现在,也有很多地区和文明仍然没有制冷技术。这些地方的人们会选择直接从奶牛的奶头中喝到新鲜的牛奶,或者把牛奶和谷物混合并发酵,以此来保存。很有趣不是吗?

不论如何,你肯定想把自家的牛奶出售给村里的其他人。但是他们能喝牛奶的时间很有限。假设你的一头奶牛一天能产出一加仑的牛奶。但是,如果太多的人来你家里购买牛奶,你可能不得不让一部分人先回家,等第二天再来购买。

同时,由于你分发有限,你甚至不能通过养殖更多奶牛来扩大你的生意。只有村里的其他人才能购买你的牛奶,你受到一些明显的限制。

相应的,如果没有缓存机制,你会受限于你的服务器的计算力。缓存就是用来加载一些静态的资源,比如:

  • 图片
  • css层叠样式表
  • html文件
  • javascript脚本文件

默认情况下,服务器必须对每一个请求做出响应。但是,一个页面的请求可能包含四个独立的请求——以上的四种类可能都有一个。当你想要请求一个较大的图像文件时,服务器可能会因为全球的大量用户(同时请求这个图片文件)而崩溃。然后,用户将会经历漫长的加载时间。

理想情况下,你希望通过存储对常见请求的响应来缓解服务器的压力。你的服务器不必处理每个独立请求,相反,缓存将会代替服务器立即做出响应。你当然可以为更多服务器买单,但是这比费用可是越来越可怕的。

什么是服务端缓存?

回到我们农场的设定中,知道如何能让经营一家牛奶农场变得容易吗?

一家带有冰箱的超市!

如此一来,人们不必去你的农场就能立刻买到牛奶。你也可以把牛奶安全地保存几个星期。

超市缓解了大量你农场的压力,因为你的奶牛不需要实时生产。超市将会处理这些需求。你只需要保证奶牛每天的生产效率即可。更好的是,附近村庄的村民都可以购买你的牛奶,因为人们总是可以在超市的冰箱里购买到你的牛奶。

就像超市一样,服务端缓存将会处理一些常用的请求,并且更快更可靠地做出响应。

在上图中我使用了一个术语——缓存代理(caching proxy),缓存代理是一个服务器,它存储用于响应公共请求的静态文件。缓存代理将拦截常见的请求并快速响应。它可以防止这些请求对主web服务器造成压力。

现在你可能有一大堆问题,比如:

  • 怎么才算常用请求?
  • 缓存代理将保存响应多长时间?

这需要在如何设置缓存上学习更多,但是现在,你应该了解的一个概念是新鲜度。缓存代理将具有在不同时间缓存的不同文件,它需要决定是否该继续提供这些文件的服务。这取决于你的缓存策略

这也和超市售卖牛奶很类似。超市经理需要决定你的牛奶上架售卖多久。缓存代理通过缓存命中率(通过缓存服务器提供的内容的百分比)来衡量其成功。

什么是CDN?

至此,现在已经有一家商店在售卖你的牛奶了。虽然这是一个巨大的进步,但是你仍然没办法把你的牛奶卖给该商店覆盖范围之外的人。如果你想扩大你的生意,你得增加更多的商店和你合作。

假设你开始向更多的超市提供牛奶,你可以在更大范围内满足客户的需要。这有点类似于一个内容交付网络,或者称为CDNCDN是一系列位于全球各地的代理服务器(就像我们之前介绍的)。

作为最终的用户,你可能觉得高速的互联网让大多数站点加载都很快。然而,这仅仅是因为这些站点使用了CDN,从而能够快速地交付静态文件。

如果你正在英格兰,并且你正在请求一个缓存在弗吉尼亚服务器上的文件,你会体会到一些延迟,因为初始信号只能沿着几千公里的电缆传输。在英国的本地缓存代理能够让这个站点加载更快。

所以,你的服务器可以向CDN网络中的每个代理服务器发送静态资源副本,它们可以处理本地请求,直到资源不再“新鲜”。一些常见的CDN提供者包括Rackspace、Akamai和Amazon Web服务。

那么浏览器缓存呢?

现在,全国(甚至全世界)的人们都可以买到你家生产的牛奶了。但现在还有一个小小的问题——顾客没法在自己家保存买来的牛奶。购买牛奶以后,顾客仍然需要尽快饮用,然后再去商店买更多。因此,这个系统仍然不能很好的服务顾客。

那有什么解决办法吗?你需要一台冰箱!

有了一台冰箱,你可以在自己家中保存牛奶,就不必反复去商场购买了。在缓存方面,我们谈论的是完全独立的存储静态资源的地方,因为它仅仅作用于客户端,或者与浏览器位于同一台计算机上。我们的代理服务器可不是在本地的。

这对于facebook或者Amazon这类你可能经常浏览的站点来说是非常好的。这对他们的服务端成本也很有好处,因为他们可以减少必须处理的请求。

有一个关键的点——我们并不是说牛奶能够“变魔术”似的直接到达你的冰箱里,你还是需要发起一个初始请求到你的服务器或者代理服务器。在这之后,你可以缓存一些文件到本地。

浏览器是怎么知道什么时候该从服务器中获取新的文件呢?如果没有这个功能,你讲永远不会获得这个文件的更新版本。

emmm,就像厂家在他们生产的牛奶包装盒上印刷上生产日期一样,服务器也会在http响应报文的头部添加某种标识符。实际上我们有4个独立的HTTP缓存系统。上面显示的场景非常类似于“保质期”的形式。在发送缓存文件之前,其他一些方法仍然需要浏览器检查服务器。

何时开始使用缓存

假设你正在开发你的第一个web应用。在你拥有大量用户之前,你可能不需要去担心缓存协议,因为服务器成本是非常低的。然而,随着你扩大规模,如果你想要快速加载你的应用,你需要使用缓存技术。

以Heroku为例,这是一个快速部署应用的平台。但是,它要求你使用单独的服务来实现缓存,就像亚马逊的CloudFront或者CloudFlare。学习这些将会花费更多时间。

在浏览器端,在你尝试更新静态资源并重新加载页面时,你可能已经体验过缓存的作用了,页面可能并没有什么变化。不论你如何刷新页面,都不会有什么变化。

这其实常常是因为浏览器端的一些缓存协议。如果你想绕过浏览器的缓存,强行从服务端重新请求资源,你可以使用Cmd+Shift+R(适用Mac)或者Ctrl+Shift+R(适用windows)。

获取更多教程

假如你喜欢这篇教程,你可以在CodeAnalogies blog上查看本文作者的更多教程。