Web应用程序的缓存策略
缓存:通过记住内容来加快网站速度
缓存是让网站更快的最有效方法之一。思路很简单:不是一次又一次地生成相同的响应,而是保存一次并重复使用。一个缓存良好的网站可以在毫秒内提供页面,而不是秒,同时将服务器负载降低几个数量级。
缓存发生的位置
缓存可以发生在多个层面。浏览器缓存文件,这样回访者就不必再次下载它们。CDN在世界各地的服务器上缓存响应,这样访问者可以从附近的位置获取数据。你的应用服务器可以缓存渲染后的页面或数据库查询结果。而数据库本身也有自己的缓存。
每个层面都有不同的特点。浏览器缓存速度快,但只对单个用户有利。CDN缓存有利于区域内的所有用户。应用程序缓存灵活,但实现起来需要付出努力。最好的方法是在尽可能多的层面进行缓存,只要对你的应用有意义。
缓存控制:告诉浏览器要记住什么
Cache-Control头部是你告诉浏览器和CDN缓存什么以及缓存多长时间的方式。像'public, max-age=31536000'这样的值告诉它们将文件缓存一年。但如果文件改变了呢?你使用一种叫做缓存破坏的技术:在文件名中包含一个版本哈希(如styles.a1b2c3.css),这样当文件改变时,URL改变,浏览器将其视为新文件。
对于变化更频繁的HTML页面,你可能会使用'no-cache'——这意味着浏览器在使用缓存版本之前应该向服务器检查。如果服务器说内容没有改变(使用ETag),浏览器可以使用缓存版本,避免完全下载。
应用程序级缓存
对于生成成本高的数据——比如数据库查询结果或外部服务的API响应——你可以在应用程序中缓存它们。Redis是最流行的选择。你将计算结果与一个键一起存储,在再次计算之前,检查缓存的结果是否存在并且仍然新鲜。
挑战在于缓存失效——知道何时清除或更新缓存。策略包括:基于时间的过期(缓存条目在设定时间后过期)、基于事件的失效(当底层数据改变时清除缓存)和直写(每次写入数据库时更新缓存)。
常见陷阱
如果不小心,缓存可能会引起问题。过时数据是最明显的——用户看到过时的信息。缓存雪崩发生在缓存条目过期且许多请求同时尝试重新生成它,导致服务器不堪重负。而调试变得更难,因为你永远不确定看到的是缓存数据还是新鲜数据。
解决方案是有一个清晰的策略。对匿名用户积极缓存,对认证用户少缓存。对关键数据使用较短的缓存时间。实现缓存预热,在缓存过期前重新生成。并且始终包含使调试成为可能的缓存头部。
