redis双写一致性
双写一致性
当我们更新了mysql中的数据后也可以同时保证redis中的数据同步更新;
在读取缓存通常按照下图的流程来进行业务操作:
20180531090217582.jpg先做一个说明,从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。
双写一致性策略:
- 策略1:先更新缓存,再更新数据库;
- 策略2:先更新数据库,再更新缓存;
- 策略3:先删除缓存,再更新数据库;
- 策略4:先更新数据库,再删除缓存;
二.四种策略存在的问题和优势
1. 先更新缓存,再更新数据库
20201126003459945.png问题:这种策略如果redis更新成功,mysql更新失败,这时造成redis脏数据问题,这种策略是绝对不能使用的,数据以数据库为准;
2. 先更新数据库,再更新缓存
2020112523350948.png问题:这种策略的主要问题就是发生在并发场景下,当线程ThreadA更新mysql后由于某种原因并没有立刻更新redis缓存,这时线程ThreadB立即将数据库和缓存都更新成功,最后ThreadA将redis中的数据进行更新,这时就会造成ThreadB对缓存的更新丢失,这是一个很严重的问题,因此不考虑;
3. 先删除缓存,再更新数据库
20201125235514385.png问题:这种策略的主要问题也是发生在并发场景下,当ThreadA更新数据库之前先将redis中的数据进行删除,在更新数据库;但是在并发场景下回有一个问题,在ThreadA还没有更新完数据库时ThreadB读取了数据库将旧数据又重新写会redis中,这样同样造成数据库和缓存数据不一致问题;
解决办法:采用双删策略,在ThreadA准备写入数据库之前将缓存删除,当ThreadA数据库中数据更新完成后再进行一次缓存删除,这样就可以解决数据不一致问题,但是要注意第二次删除一定要保证时间上晚于数据库更新成功时间;值得注意的是延迟删除的时间间隔一定要大于操作的时间周期;
4. 先更新数据库,再删除缓存
20201126001558733.png问题:这种策略的主要问题同样是发生在并发场景下,当ThreadA首先进行读数据库,准备将数据写入缓存,这时ThreadB更新数据库并且立刻执行了缓存删除,最后ThreadA才将旧数据同步到redis缓存中,同样会造成数据库和缓存数据不一致问题;
一般来说这种情况出现的概率很低,因为写操作时间大概率要比读操作时间长很多;
解决办法:解决上述问题的办法还是使用延迟双删策略,但要注意在ThreadB的第二次删除时间间隔一定要大于ThreadA的读取数据的时间周期;