Cache
使用场景
高性能
若从数据库查询(复杂查询、跨表跨库查询)一个数据比较耗时,而且数据在短时间内不会变,那么可以把查询结果做缓存。
由于缓存是内存,所以性能大大由于数据库。
高并发
缺点
缓存与数据库双写不一致
Cache Aside Pattern:
读,先读缓存,再读数据库。
更新,先删除缓存,再更新数据库。选择删除而不是跟新缓存的原因:很多时候是经过复杂查询、计算后的结果,更新的话成本太大。其实使用的是 lazy 的思想。
情况一
场景:先修改数据库,再删除缓存,如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据出现不一致。
解决方案:先删除缓存,再修改数据库。
情况二
场景:先删除缓存,然后去修改数据库,此时还没修改完成,一个请求过来,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中,此时数据变更的程序完成了数据库的修改。
解决方案:
缓存雪崩
缓存挂了,所有请求瞬时全部到数据库,导致数据库宕机。
解决方案:
保证缓存高可用。
系统内缓存,比如 ehcache。
在请求数据库层做限流+降级。比如 Hystrix。
缓存持久化,可以尽快恢复缓存。
缓存穿透
由于不正确的请求(比如黑客攻击),所有的请求都命中不到缓存,导致全部请求到数据库。比如数据库中 id 为 1 -100,发出请求 id 为 -1。
可以把数据库查不到的数据写一个空值到缓存里面去。
缓存并发竞争
场景:多个服务同时对缓存中的某个 key 做更新,没有按照期望的顺序执行,所以最终的缓存数据不正确。
解决方案:分布式锁+时间戳。
Last updated