mysql和redis双写一致性策略分析
一.什么是双写一致性
当我们更新了mysql中的数据后也可以同时保证redis中的数据同步更新;
数据读取的流程:
1.读取redis,如果value!=null,直接返回;
2.如果redis中value=null,读取mysql中数据对应的value,将key-value保存在redis中;
双写一致性策略:
策略1:先更新缓存,再更新数据库;
策略2:先更新数据库,再更新缓存;
策略3:先删除缓存,再更新数据库;
策略4:先更新数据库,再删除缓存;
二.四种策略存在的问题和优势
1.先更新缓存,再更新数据库
问题:这种策略如果redis更新成功,mysql更新失败,这时造成redis脏数据问题,这种策略是绝对不能使用的;
2.先更新数据库,再更新缓存
问题:这种策略的主要问题就是发生在并发场景下,当线程ThreadA更新mysql后由于某种原因并没有立刻更新redis缓存,这时线程ThreadB立即将数据库和缓存都更新成功,最后ThreadA将redis中的数据进行更新,这时就会造成ThreadB对缓存的更新丢失,这是一个很严重的问题;
3.先删除缓存,再更新数据库
问题:这种策略的主要问题也是发生在并发场景下,当ThreadA更新数据库之前先将redis中的数据进行删除,在更新数据库;但是在并发场景下回有一个问题,在ThreadA还没有更新完数据库时ThreadB读取了数据库将旧数据又重新写会redis中,这样同样造成数据库和缓存数据不一致问题;
解决办法:采用双删策略,在ThreadA准备写入数据库之前将缓存删除,当ThreadA数据库中数据更新完成后再进行一次缓存删除,这样就可以解决数据不一致问题,但是要注意第二次删除一定要保证时间上晚于数据库更新成功时间;值得注意的是延迟删除的时间间隔硬顶要大于操作的时间周期;
4.先更新数据库,再删除缓存
问题:这种策略的主要问题同样是发生在并发场景下,当ThreadA首先进行读数据库,准备将数据写入缓存,这时ThreadB更新数据库并且立刻执行了缓存删除,最后ThreadA才将旧数据同步到redis缓存中,同样会造成数据库和缓存数据不一致问题;
一般来说这种情况出现的概率很低,因为写操作时间大概率要比读操作时间长很多;
解决办法:解决上述问题的办法还是使用延迟双删策略,但要注意在ThreadB的第二次删除时间间隔一定要大于ThreadA的读取数据的时间周期;
三.扩展
1.采用延迟双删策略时如果删除失败了如何进行处理?
消息队列
2.如何使用Canal保证数据库与缓存数据的实时一致性?
来源:oschina
链接:https://my.oschina.net/u/4313604/blog/4757399