使用Redis的缓存更新策略

(以两个更新年龄为20和为21的并发请求为案例)

1.更新数据库,然后更新缓存

请求A更新数据库为20,接着准备更新缓存为20。在更新缓存前,请求B进来,更新数据库为21,然后更新缓存为21。这时,请求A的更新缓存操作才开始,更新了缓存为20。这就导致数据库里是新数据21,而缓存里是旧数据20。客户只能查到旧数据。

2.更新缓存,然后更新数据库

请求A更新缓存为20,接着准备更新数据库为20。在更新数据库为20前,请求B进来,更新缓存为21,更新数据库为21,然后请求A才更新数据库为20。这时,缓存里是新数据21,数据库里是旧数据20。

更新数据时,将更新缓存换为删除缓存,等到查询数据时,如果缓存未命中,再去查询数据库,写入缓存。

(为什么将更新缓存换为删除缓存?)

①用户一更新数据就去更新缓存,如果用户一直不去查,更新频率又很高,就会有很多无效写操作。

②删除缓存是一种懒思想的应用。删除一个数据,相较于更新一个数据,更加轻量级,出错概率更小。

那么,删除缓存和更新数据库,谁先呢?

(以一个更新年龄的请求和一个查询年龄的请求为案例)

1.删除缓存,然后更新数据库

请求A要将数据20改为21,先删除缓存20,准备更新数据库为21。在这之前,请求B进来,查询,未命中缓存,去数据库查到20,写入缓存为20。然后,请求A才更新数据库为21。这时,缓存中为20,数据库为21。

2.更新数据库,再删除缓存

查询请求A进来,未命中缓存,读取数据库数据为20,准备写入缓存数据为20。在这之前,请求B进来更新数据20为21,更新了数据库为21,删除了缓存(但这时缓存里没东西,所以是个空删除),然后请求A才将20写入缓存。这时,缓存中为20,数据库中为21。

仍然是两种方案都不行,但数据库操作一般比较耗时,所以写入缓存在数据库操作完成之后才进行的概率很低,即第二种失误发生的概率较低,故选用先更新数据库,再删除缓存的方案。

但如果业务对缓存命中率要求较高的话,我们可以采用更新缓存+更新数据库的方案,因为这样缓存命中率才会比较高。但双更新的方案之前分析过会出现并发问题,因此要对其加锁或者加较短的过期时间来应对。

对于【先删除缓存,再更新数据库】的方案,在高并发状况下的缓存不一致问题,有“延迟双删”的解决方案。

具体操作是:①删除缓存;②更新数据库;③线程休眠一段时间;④再次删除缓存

之前就是因为先删,在更新前另一个请求进来查询,未命中缓存,然后去数据库查,又写入缓存,然后数据库才更新完成。才导致缓存是旧数据,数据库是新数据。线程休眠一段时间,是为了留时间给查询的并发请求将旧数据尽管写到缓存中,然后我再次删除缓存,这样缓存就不会是旧数据了,下次别的请求来查,查不到,就会去数据库查新数据。

但延迟双删要让线程休眠时间大于查询请求查询又写入缓存的时间,这个时间不好估计。

在【更新数据库,然后删除缓存】方案中,我们要保证删除缓存成功。因为如果删除缓存失败,缓存中是旧数据,数据库中是新数据。下次查询请求过来,因为命中了缓存,会一直查到旧数据。就算设置了过期时间,也有一定延时。

为了保证删除缓存成功,有两种解决方案:

①使用消息队列的重试机制:将删除缓存要操作的数据加入消息队列,如果删除失败,从消息队列重新读取数据,然后再次删除。成功删除后,要把数据从消息队列中移除,避免重复操作。(这种方案对代码侵入性较强)

②使用MySQL的binlog日志

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值