方案1:同步删除
核心流程:
1、先更新数据库
2、删除缓存数据
正常流程图:
解决问题:
1.能很大程度上保证缓存数据和数据库一致
2.更新缓存改为删除缓存,不用考虑缓存和数据库事务问题
存在问题:
1.缓存没有数据要查询数据库,存在一定的开发工作量(目前没有做这块内容)
2.缓存删除后,会造成很多请求到数据库,数据库压力瞬间增大(可使用分布式+自旋锁进行解决)
3.存在并发问题,并且脏数据会存在很长时间(异常流程图)
异常流程图:
线程A更新数据库和删除缓存都完成后,但没有提交事务,机器进行了GC等,等待操作。
线程B查询缓存发现没有数据,查询数据库拿到线程A还没提交的脏数据,这时候线程A提交事务,线程B把脏数据存到了缓存
方案2: 延迟双删
核心流程:
1、先更新数据库
2、同步删除缓存数据
3、发送MQ延迟再删除缓存
正常流程图:
基于方案1异常情况
解决问题:
1.能很大程度上保证缓存数据和数据库一致
2.更新缓存改为删除缓存,不用考虑缓存和数据库事务问题
3.极端情况下脏数据只会存在相当短的时间窗口
存在问题:
1.缓存没有数据要查询数据库,存在一定的开发工作量(目前没有做这块内容)
2.缓存删除后,会造成很多请求到数据库,数据库压力瞬间增大(可使用分布式+自旋锁进行解决)
3.并不能根本上解决数据不一致问题,极端情况还会存在数据不一致问题
4.延迟时间较难评估,过长会造成读取脏数据时间窗口过长,过短可能起不到删除脏数据的问题
异常流程图:
线程A更新数据库和删除缓存都完成后,但没有提交事务,机器进行了GC等,等待操作。
线程B查询缓存发现没有数据,查询数据库拿到线程A还没提交的脏数据,这时候线程A提交事务,线程B把脏数据存到了缓存
线程A发送延迟删除缓存MQ,在删除期间线程C查询缓存为脏数据
方案3: 同步删除+binlog删除+MQ重试
核心流程:
1、先更新数据库
2、删除缓存数据
3、监控binlog再次删除缓存,删除失败重试
正常流程图:
解决问题:
1.能很大程度上保证缓存数据和数据库一致
2.更新缓存改为删除缓存,不用考虑缓存和数据库事务问题
3.可以做到收拢所有操作数据库操作,不存在代码丢删除缓存逻辑
4.删除脏缓存较实时
存在问题:
1.缓存没有数据要查询数据库,存在一定的开发工作量
2.缓存删除后,会造成很多请求到数据库,数据库压力瞬间增大(可使用分布式+自旋锁进行解决)
3.开发和维护成本较高
4.极端情况下脏数据只会存在相当短的时间窗口
异常流程图:
线程A更新数据库和删除缓存都完成后,但没有提交事务,机器进行了GC等,等待操作。
线程B查询缓存发现没有数据,查询数据库拿到线程A还没提交的脏数据,这时候线程A提交事务,线程B把脏数据存到了缓存
线程C查询缓存并获得脏数据
最终binlog会异步删除脏数据