缓存是软件工程中最诱人的工具之一。只需很少的努力,您就可以将缓慢的操作转变为即时响应。系统变得更快,基础设施呼吸,用户微笑。看起来就像魔法一样。
正是因为缓存看起来像魔法,才会造成如此大的损害。它如此轻松地解决了性能问题,以至于人们将缓存分散到各处,却没有意识到他们正在用一个可见的问题(缓慢)来换取一个不可见的问题(错误的数据)。错误的数据比缓慢的数据更糟糕。
这是良好使用缓存的快速指南。这个想法并不是要穷尽这个主题,而是为您提供区分有帮助的缓存和成为陷阱的缓存的标准。正如经典的计算笑话所说,只有两个难题:缓存失效、命名事物和一加一错误。
缓存的作用是什么,一句话
缓存是保存昂贵操作的结果以供重用,而不是每次都重做该操作。您计算一次,保存它,并在下次提供保存的答案时。
“昂贵”的操作可能是繁重的数据库查询、对外部服务的调用、复杂的计算或页面的呈现。收获来自于不重复工作。当多次请求相同的结果并且变化很小时,缓存几乎总是一个好主意。
关键词是“变化不大”。这就是所有复杂性所在,也是大多数人出错的地方。
良好实践:缓存读取较多且更改较少的内容
理想的候选缓存有两个特征:访问频繁且很少更改。考虑产品类别列表、系统配置、用户的公共配置文件。这类数据一直在读取,时不时更新,完美的缓存。
坏缓存候选者则相反:数据每时每刻都在变化,或者其准确性实时至关重要。银行帐户的余额、购买时可用的库存、主动谈判中的价格、缓存可能会给用户一个不再真实的数字,从而产生真正的后果。
缓存任何内容之前的实际问题是:如果用户看到过期了几秒或几分钟的值会发生什么?如果答案是“没什么大不了的”,就缓存。如果答案是“一个严重的问题”,请三思。
真正的问题:失效
将数据放入缓存中很简单。困难的部分是知道何时删除或更新。这就是失效问题,几乎所有缓存错误都是由此产生的。
有两种基本策略,并且各有其用处。第一个是时间过期:数据在缓存中保存一段定义的时间,然后被丢弃。简单、强大且足以满足大多数情况。您接受数据可能会过时(例如五分钟),然后继续您的生活。
第二个是事件失效:当数据发生变化时,你主动移除或者更新缓存的版本。它更精确,但也更脆弱,它要求数据的每一次变化都记得通知缓存,而它所需要的只是一条被遗忘的路径让用户无限期地看到旧的信息。
快速指南的最佳实践:在容差允许的情况下首选定时过期。它更简单,更能抵抗人为错误,并避免缓存“忘记”更新的错误。当准确性真正证明复杂性合理时,保留事件失效。
良好实践:定义缓存失败时会发生什么
缓存是一个额外的层,额外的层会失败。缓存服务器可能会停机、不可用或速度缓慢。许多人忘记回答的问题是:那么系统会停止吗?
做得好的缓存是一种优化,而不是依赖。如果缓存消失,应用程序必须继续工作,虽然速度可能较慢,但仍然可以从原始源搜索数据。当整个系统因为缓存崩溃而崩溃时,你没有进行优化;存在伪装成性能改进的单点故障。
还有一个危险的细节:当缓存立即清空时,所有请求都会同时到达原始源,并且过载可能会精确地破坏缓存所保护的内容。这是一个已知的效果,值得在设计恢复时考虑到它,以便系统重新加热缓存而不会被淹没。
批判反思:缓存隐藏错误问题
缓存的一种用途在技术上是正确的,但在策略上却是懒惰的:通过缓存来隐藏做得很差的查询。查询速度慢是因为写得不好或者数据库建模不好,而不是纠正原因,而是将缓存扔在上面。它一直有效,直到缓存过期,直到出现不可缓存的情况,直到问题消失。
缓存应该加速已经高效的内容,而不是弥补低效的内容。当您发现自己使用缓存来使某些应该修复的问题变得可以忍受时,值得停下来并查看原因。在这种情况下,缓存是推迟债务,而不是偿还债务。
还有认知成本。每个缓存层都是数据可能过期的又一处,也是当出现奇怪情况时可以进行调查的又一处。 “为什么该用户看到旧信息?”是最令人沮丧的调试问题之一,正是因为在出现问题之前缓存是不可见的。太多的缓存会将一个简单的系统变成一个版本控制难题。谨慎使用,记录你所在的位置,并且更喜欢较少易于理解的层而不是许多神秘的层。
还剩下什么
缓存是一个强大的工具,但同样经常被滥用。使用得当,它会留下快速且廉价的系统。它被滥用,它提供错误的信息,隐藏真正的问题并产生难以跟踪的错误。
好的实践可以概括为几行:缓存读取较多且更改较少的内容;更喜欢定时过期而不是手动失效;确保系统在没有缓存的情况下生存;并且永远不要使用缓存来隐藏应该解决的问题。剩下的就是微调了。
如果您面临性能问题并考虑将缓存作为解决方案,则值得首先了解瓶颈是否实际上来自重复读取或更深层次的原因。博客上还有其他有关后端、性能和架构的文本,可以更深入地研究这些选择。
另请阅读
- [应用后端:小团队不能犯错误的良好实践00
- [应用程序中的缓存:良好实践和基础知识1
- [应用程序中的缓存:良好实践和基本步骤2
- [应用程序中的缓存3
- [应用程序架构:可扩展系统完整指南4
- [应用程序可扩展性:完整的技术指南5
