面试官:Redis和Mysql如何保证数据一致性?
点击关注公众号:互联网架构师,后台回复 2T获取2TB学习资源!
前言
1.缓存不一致是如何产生的
如果数据一直没有变更,那么就不会出现缓存不一致的问题。
通常缓存不一致是发生在数据有变更的时候。因为每次数据变更你需要同时操作数据库和缓存,而他们又属于不同的系统,无法做到同时操作成功或失败,总会有一个时间差。在并发读写的时候可能就会出现缓存不一致的问题(理论上通过分布式事务可以保证这一点,不过实际上基本上很少有人这么做)。
虽然没办法在数据有变更时,保证缓存和数据库强一致,但对缓存的更新还是有一定设计方法的,遵循这些设计方法,能够让这个不一致的影响时间和影响范围最小化。
2.缓存更新的几种设计
缓存更新的设计方法大概有以下四种:
先删除缓存,再更新数据库(这种方法在并发下最容易出现长时间的脏数据,不可取)
先更新数据库,删除缓存(Cache Aside Pattern)
只更新缓存,由缓存自己同步更新数据库(Read/Write Through Pattern)
只更新缓存,由缓存自己异步更新数据库(Write Behind Cache Pattern)
接下来详细介绍一些这四种设计方法
2.1 先删除缓存,再更新数据库
这种方法在并发读写的情况下容易出现缓存不一致的问题
如上图所示,其可能的执行流程顺序为:
客户端1 触发更新数据A的逻辑
客户端2 触发查询数据A的逻辑
客户端1 删除缓存中数据A
客户端2 查询缓存中数据A,未命中
客户端2 从数据库查询数据A,并更新到缓存中
客户端1 更新数据库中数据A
可见,最后缓存中的数据A跟数据库中的数据A是不一致的,缓存中的数据A是旧的脏数据。
因此一般不建议使用这种方式。
2.2 先更新数据库,再让缓存失效
这种方法在并发读写的情况下,也可能会出现短暂缓存不一致的问题
如上图所示,其可能执行的流程顺序为:
客户端1 触发更新数据A的逻辑
客户端2 触发查询数据A的逻辑
客户端3 触发查询数据A的逻辑
客户端1 更新数据库中数据A
客户端2 查询缓存中数据A,命中返回(旧数据)
客户端1 让缓存中数据A失效
客户端3 查询缓存中数据A,未命中
客户端3 查询数据库中数据A,并更新到缓存中
可见,最后缓存中的数据A和数据库中的数据A是一致的,理论上可能会出现一小段时间数据不一致,不过这种概率也比较低,大部分的业务也不会有太大的问题。
2.3 只更新缓存,由缓存自己同步更新数据库(Read/Write Through Pattern)
这种方法相当于是业务只更新缓存,再由缓存去同步更新数据库。一个Write Through的 例子如下:
客户端1 触发更新数据A的逻辑
客户端2 触发查询数据A的逻辑
客户端1 更新缓存中数据A,缓存同步更新数据库中数据A,再返回结果
客户端2 查询缓存中数据A,命中返回
客户端1 触发更新数据A的逻辑
客户端2 触发查询数据A的逻辑
客户端1 更新缓存中的数据A,返回
客户端2 查询缓存中的数据A,命中返回
缓存异步更新数据A到数据库中
总结
最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。
正文结束
推荐阅读 ↓↓↓
正文结束