赞
踩
总结:无论是「先更新数据库,再更新缓存」,还是「先更新缓存,再更新数据库」,这两个方案都存在并发问题,当两个请求并发更新同一条数据的时候,可能会出现缓存和数据库中的数据不一致的现象。
- 我们的业务对缓存命中率有很高的要求,我们可以采用「更新数据库 + 更新缓存」的方案,因为更新缓存并不会出现缓存未命中的情况。
问题
- 在两个更新请求并发执行的时候,会出现数据不一致的问题,因为更新数据库和更新缓存这两个操作是独立的,而我们>又没有对操作做任何并发控制,那么当两个线程并发更新它们的话,就会因为写入顺序的不同造成数据的不一致。
解决办法
在更新缓存前先加个分布式锁,保证同一时间只运行一个请求更新缓存,就会不会产生并发问题了,当然引入了锁后,对于写入的性能就>会带来影响。
在更新完缓存时,给缓存加上较短的过期时间,这样即时出现缓存不一致的情况,缓存的数据也会很快过期,对业务还是能接受的。
先更新数据库,还是先删除缓存,叫Cache Aside 策略
,中文是叫旁路缓存策略
。
该策略又可以细分为「读策略」
和「写策略」
。
写策略的步骤
:
读策略的步骤
:
缓存数据加上了「过期时间」,就算在这期间存在缓存数据不一致,有过期时间来兜底,这样也能达到最终一致。
所以,「先更新数据库 + 再删除缓存」
的方案,是可以保证数据一致性的。
问题
解决办法
#删除缓存
redis.delKey(X)
#更新数据库
db.update(X)
#睡眠
Thread.sleep(N)
#再删除缓存
redis.delKey(X)
建议使用「先更新数据库,再删除缓存」的方案。
「先更新数据库 + 再删除缓存」
的方案,是可以保证数据一致性的。但是在删除缓存(第二个操作)的时候失败了,导致缓存还是旧值,而数据库是最新值,虽然加了过期时间,但是也需要过一会才生效,所以还会造成数据库和缓存数据不一致的问题。解决办法
消息队列
,将第二个操作(删除缓存)要操作的数据加入到消息队列,由消费者来操作数据。
删除缓存失败
,可以从消息队列中重新读取数据,然后再次删除缓存,这个就是重试机制。当然,如果重试超过的一定次数,还是没有成功,我们就需要向业务层发送报错信息了。删除缓存成功
,就要把数据从消息队列中移除,避免重复操作,否则就继续重试。Canal 原理
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。