如果您进行大量读取但很少更新,则缓存非常有用。数据库中的数据更改越频繁,缓存系统的问题就越大。缓存确实会给您的代码库增加一定的复杂性,这可能会很难处理。在最坏的情况下,它甚至会减慢您的网站速度。
最重要的问题是:
什么时候必须使缓存失效?它什么时候变得陈旧?在大多数情况下,如果数据库查询返回的行与缓存该页面时的行不同。但你怎么知道呢?你没有(也许有办法,但我想不出任何自动取款机),因为要检查这一点,你可能必须查询结果进行比较。
你可以做什么:
-
每次更新数据库的相关部分时清除所有缓存
如果您的数据库很少更新(每小时、每天、每周),这确实是可能的。但如果变化不断发生,那就毫无用处了。大多数网络项目都是这种情况。
-
发生某些事情后清除缓存的项目
这只适用于不需要立即反映更改的情况(例如,如果存在则无关紧要)不正确一段时间的数据)。在这种情况下,如果某个项目早于 X 分钟,或者发生了超过 Y 的综合浏览量,您只需清除该项目的缓存即可。
-
仅清除相关部分
在这里,您必须弄清楚更新数据库时缓存的哪些部分受到影响。如果做得正确,变化会立即反映出来,同时性能也会提高。
最有可能的是选项 3:你必须找出答案。因此,我们以网络博客的经典案例为例,它由首页、存档页面和每个条目的详细信息页面组成。
更改是通过以下方式引入的:管理面板(条目的 CRUD)和评论
如果条目被编辑或删除,您必须清除缓存:
- 首页,如果条目是新的
- 相关存档页面(如果条目是旧的)
- 条目的详细信息页面
如果有人发表评论,您只需清除详细信息页面,但前提是索引或存档中未显示评论数量。否则,与 Entry-crud 相同。
如果站点范围内的某些内容发生更改,则必须清除整个缓存(糟糕!)
现在,让我们考虑一下条目粗略和存档。如果存档的类型为“每月一页”,则清除该条目所属的月份。但如果存档是条目 1-10、11-20、21-30...,则很可能必须重建整个存档缓存。
等等 ...
一些问题:
-
如果您没有正确识别所有受影响的部分,则可能会导致过时的数据和/或(未)死链接。
-
如果更新发生得太频繁,则构建缓存是额外的工作,因为当下一个页面浏览发生时,缓存很可能再次过时,并且无论如何都必须重建。
-
页面的某些部分不适合缓存,例如(自定义)搜索功能。如果缓存在其他地方工作,一切都会很快而且很棒,但搜索仍然非常慢。
-
如果在发生大量请求时必须清除整个缓存,这可能会出现问题。然后它可能会阻塞您的服务器,因为缓存未命中通常比页面一开始就没有缓存的代价更高。更糟糕的是,如果有 3 个请求进来,并且第一个请求在处理其他两个请求之前无法缓存页面,则缓存会被请求 3 次而不是一次。
我的建议:
-
优化您的数据库。按键和配置好吗?也许它可以在没有缓存的情况下工作。
-
优化您的查询。 “解释选择”!
-
只缓存页面的一部分——昂贵的部分。使用 str_replace 和占位符填充小的、廉价的更改
-
如果一切正常,请使用 apc 或 memcached 而不是文件(文件通常效果很好,但 apc/memc 更快)。您还可以使用数据库来缓存数据库,通常效果很好!
-
您正在构建一个惰性缓存系统还是一个急切的缓存系统?惰性表示:在页面第一次请求时构建缓存,急切表示:在更新后立即构建缓存。
嗯,我没有什么真正的建议给你。太依赖于问题了:)
update
有一个对密钥为 256 的博客条目的请求。它显示了博客条目、评论以及当前登录的用户。查询条目和评论以及格式化所有文本和所有内容的成本很高。当前登录的用户驻留在会话中。
首先,为要缓存的部分创建一个唯一的键。在这种情况下,缓存键可能是条目的数据库 ID(带有一些前缀和后缀)。
所以,缓存文件的名称应该是cache/blogentry_256.tmp
。检查该文件是否存在。
-
如果不存在,则执行所有昂贵的查询和格式化,在当前用户的名称所在位置保留一个占位符(例如 {username}),并将结果保存到cache/blogentry_256.tmp
。请注意,不要将任何不应向每个人显示或根据每个请求进行更改的数据写入此文件。
-
现在,读取文件(或重用 1 中的数据)并将用户名 str_replace 到占位符中。echo
结果。
如果条目被更改或有人评论,您必须删除带有条目 id 的缓存文件。
这是惰性缓存 - 仅当用户请求页面时才会构建缓存。请小心 - 如果用户在评论中输入 {username},它也会被插入那里!这意味着,您必须转义缓存数据并在 str_replacing 之后取消转义。该技术也适用于 memcached 或 apc。
问题:您必须围绕缓存决策构建您的设计。例如如果你想显示“5分钟前发布的评论”而不是“5月6日下午3:42添加的评论”,那么你就有麻烦了。