预防缓存击穿

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

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

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

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

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

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

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

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

没了。


更多文章
  • 使用shairport-sync搭建airplay音频服务器
  • 搭建aria2服务器
  • VirtManager Windows自适应屏幕
  • 使用btrfs组建RAID1
  • Swagger? 不好用
  • Golang/Python最佳实践
  • 读《毛泽东选集》
  • GORM源码阅读与分析
  • 随想
  • Golang中的错误处理
  • Golang 的槽点
  • 一个想当然的bug
  • 读《稀缺》
  • 读《影响力》
  • 读《自控力》