JAVA面试总结-Redis篇章(四)——双写一致性
- 问:redis 做为缓存,mysql的数据如何与redis进行同步呢?
- 第一种情况,如果你的项目一致性要求高的话 采用以下逻辑
- 我们应该先删除缓存,再修改数据库,还是先修改数据库,再删除缓存呢,以下有两种情况
- 1.先删除缓存,再操作数据库
- 正常情况
- 异常情况
- 2.先更新数据库,再操作缓存
- 正常情况
- 异常情况
- 解决办法 :采用延迟双删
- 问:为什么要删除两次缓存?
- 由以上可知,先删除缓存,再修改数据库会导致有脏数据产生,采用延时再进行删除缓存,可以避免这种问题产生。
- 问:为什么要删除两次缓存?
- 由以上可知,先删除缓存,再修改数据库会导致有脏数据产生,采用延时再进行删除缓存,可以避免这种问题产生。
- 问:为什么要延时删除?
- 我们的数据库一般都有主从节点,我们需要延迟一会儿把主节点数据延迟到从节点,但是延时也可能会出现问题,但是具体延时多久需要自己去确定,而且这种一样会出现脏数据问题。
- 问:有没有其他方案保持数据强一致?
- 采用分布式锁
- 采用锁可以保证数据强一致性,但是性能会降低
- 具体代码实现
- 读写锁(读锁)
- 排它锁(写锁)
- 只有要求强一致的情况下,才会使用锁
- 第二种情况,如果你的项目能够允许数据的短暂不一致,采用以下逻辑
- 异步通知
- 1 使用MQ
- 2 基于Canal的异步通知
问:redis 做为缓存,mysql的数据如何与redis进行同步呢?
第一种情况,如果你的项目一致性要求高的话 采用以下逻辑
我们应该先删除缓存,再修改数据库,还是先修改数据库,再删除缓存呢,以下有两种情况
1.先删除缓存,再操作数据库
正常情况
一开始数据库和缓存中都是10,先删除缓存,更新数据库为20,之后线程2再查询缓存,未命中去查询数据库,查到则写入缓存
异常情况
一开始数据库和缓存中都是10,先删除缓存,此时刚好有一个线程来进行查询,缓存中没有数据,去查询数据库,此时数据库未更新,查询到的是旧数据,再写入缓存的也是旧数据,最后更新数据库为20,此时导致缓存和数据库内容不一致
2.先更新数据库,再操作缓存
正常情况
一开始数据库和缓存中都是10,先更新数据库,再删除缓存,之后来了一个线程来进行查询,缓存中没有就去查询数据库,之后写入缓存,数据是一致的
异常情况
一开始数据库和缓存中都是10,如果有个线程在修改数据库之前进行查询,此时数据库未更新,查询到的是10,之后进行更新数据库,再删除缓存,然后线程1会把刚刚查到的旧数据写入缓存,导致数据不一致。
解决办法 :采用延迟双删
问:为什么要删除两次缓存?
由以上可知,先删除缓存,再修改数据库会导致有脏数据产生,采用延时再进行删除缓存,可以避免这种问题产生。
问:为什么要删除两次缓存?
由以上可知,先删除缓存,再修改数据库会导致有脏数据产生,采用延时再进行删除缓存,可以避免这种问题产生。
问:为什么要延时删除?
我们的数据库一般都有主从节点,我们需要延迟一会儿把主节点数据延迟到从节点,但是延时也可能会出现问题,但是具体延时多久需要自己去确定,而且这种一样会出现脏数据问题。
问:有没有其他方案保持数据强一致?
采用分布式锁
采用锁可以保证数据强一致性,但是性能会降低
具体代码实现
读写锁(读锁)
排它锁(写锁)
只有要求强一致的情况下,才会使用锁
第二种情况,如果你的项目能够允许数据的短暂不一致,采用以下逻辑
异步通知
1 使用MQ
2 基于Canal的异步通知
这种方法代码侵入较小