Cache

使用场景

高性能

若从数据库查询(复杂查询、跨表跨库查询)一个数据比较耗时,而且数据在短时间内不会变,那么可以把查询结果做缓存。

由于缓存是内存,所以性能大大由于数据库。

高并发

缺点

缓存与数据库双写不一致

Cache Aside Pattern:

  • 读,先读缓存,再读数据库。

  • 更新,先删除缓存,再更新数据库。选择删除而不是跟新缓存的原因:很多时候是经过复杂查询、计算后的结果,更新的话成本太大。其实使用的是 lazy 的思想。

情况一

场景:先修改数据库,再删除缓存,如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据出现不一致。

解决方案:先删除缓存,再修改数据库。

情况二

场景:先删除缓存,然后去修改数据库,此时还没修改完成,一个请求过来,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中,此时数据变更的程序完成了数据库的修改。

解决方案:

缓存雪崩

缓存挂了,所有请求瞬时全部到数据库,导致数据库宕机。

解决方案:

  • 保证缓存高可用。

  • 系统内缓存,比如 ehcache。

  • 在请求数据库层做限流+降级。比如 Hystrix。

  • 缓存持久化,可以尽快恢复缓存。

缓存穿透

由于不正确的请求(比如黑客攻击),所有的请求都命中不到缓存,导致全部请求到数据库。比如数据库中 id 为 1 -100,发出请求 id 为 -1。

可以把数据库查不到的数据写一个空值到缓存里面去。

缓存并发竞争

场景:多个服务同时对缓存中的某个 key 做更新,没有按照期望的顺序执行,所以最终的缓存数据不正确。

解决方案:分布式锁+时间戳。

Last updated