当你既要更新数据库,又要更新缓存的时候,就涉及到一致性的问题,如何保证两者能同时成功呢?
会出现缓存中的数据是旧值。
缓解方法
这种情况总体对业务影响较小。一般在生产环境中,也推荐大家采用该模式。
线程A发现缓存为空,查询数据库,准备回填缓存的时候发生了阻塞。
线程B发现缓存为空,查询数据库,此时看到的值为新值,因为其他线程修改了数据,回填缓存。
线程A苏醒过来,回填缓存,此时是旧值。
会出现缓存中的数据是旧值。
如果要想解决这种问题,那就只能在读缓存的时候加分布式锁,当然在这个过程中可以做一些优化,具体可以使用 rockscache,它的说明,具体原理图
前面说到,我们应该先更新数据库,再删除缓存,那么对于热点数据,突然把缓存删了会导致缓存击穿,对数据库造成巨大冲击,针对这种情况,我们需要限制最终去到数据库的流量,我们可以在进程内部加锁,也就是单飞模式,这样每个进程只有一个查询数据库的操作,当然如果你的项目服务器很多,那么对数据库的查询也会很多,那么只能使用分布式锁来加以限制。
如果请求的数据在数据库中也不存在,那么为了节省缓存空间一般是不会缓存它的,这就会导致这些请求都会一次次的被打到数据库,这就是缓存穿透。
首先,如果预防住了缓存击穿,那么在一点程度上也减轻了缓存穿透的危害,除此之外,我们还可以引入布隆过滤器将这些恶意的key存起来。
如果在某一个时刻,缓存大面积同时过期,那么这就是缓存雪崩,预防的方式也很简单,为不同的key设置不同的过期时间,过期时间最好带一个随机数。