预防缓存击穿

一般来说,传说中的高并发解决方案的一大法宝就是使用缓存。没有缓存时,我们的请求是这样的:

(请求) -> (网关) -> (后端应用) -> (数据库)
           /    \<--/         \<--/
(响应) <- /

可以看到,每次都是来一个请求,就查一次数据库。数据库最坏的情况下要在磁盘上查数据,因此当大量流量走向这种情况下的数据库, 数据库就抗不住了,接着就会带着后端应用一起挂。

而当我们使用缓存时,后端应用会先检查是否有缓存,如果有缓存,那么直接返回缓存,否则则查询数据库,并将结果缓存起来留待下次 使用,然后返回数据。

这里有一个漏洞,那就是,如果我知道某个查询无法查到数据,而应用按照上面的逻辑,有结果才缓存,否则不缓存。就可以绕过缓存, 直接把流量打到数据库上了。

预防这种情况的方法也很简单,那就是,就算没有查到结果,也在缓存里记一条。当下次再查询的时候,就还是可以从缓存里拿到一个 “没有结果”的结果了。带来的弊端就是,当数据更新之后,因为缓存里存了”没有结果”,所以拿到的还是没有结果,那咋办呢?解决方案 也挺简单,给缓存结果加TTL(就算是正常的,我们也要加TTL的嘛,不是吗?)。

请注意,这也不是万能的解决方案。更多的还是要在应用层做好校验,尽可能过滤掉本就不存在的数据。否则,因为缓存不存在的东西, 不存在的东西是可以无限构造的,这样的话,挂的可能不是DB,而是缓存了(再多的内存也不够用呀)。

当然了,上面说的这种方式,只是众多缓存策略中的一种,和它所面临的问题。缓存策略还有其他很多种,比如主动缓存等等。只是上面 所说的这种缓存方式比较常用。

没了。


更多文章
  • 数据库事务
  • 把网站去掉CSS之后
  • 处理并发的方式
  • 常见的索引方式
  • Golang 实践经验
  • 高性能MySQL笔记第一章
  • 面试的一些技巧
  • HTTP/2 简介
  • 独立运营博客一年的一些数据分享
  • To B(usiness) 和 To C(ustomer)
  • 常见的软件架构套路
  • Cookie 中的secure和httponly属性
  • Google Ads使用体验
  • Go的custom import path
  • 如何挖掘二级子域名?