redis 缓存和 mysql 数据一致性
场景:update set value = 10 where value = 9
1) redis更新成功:redis value = 10
2)数据库更新失败:mysql value = 9
3)数据不一致
2、先更新数据库再更新redis
场景: A进程update set value = 10 where value = 9 ;B进程 update set value = 11 where value = 9;
1)A 进程先更新数据库,还未写入缓存:mysql value = 10 ;redis value = 9
2)B 进程更新数据库并且提交事务,写入缓存:mysql value = 11;redis value = 11;
3)A 进程处理完请求提交事务,写入缓存:redis value = 10;
4)最终 mysql value = 11; redis value = 10
3、先删除缓存再更新数据库
场景:A进程update set value = 10 where value = 9 ;B进程查询value;
1)A 进程先删除缓存 还没来得及修改数据或者事务未提交
2)B 进程开始查询,没有命中缓存,所以查库并写入缓存 redis value = 9
3)A 进程更新数据库完成 mysql value = 10
4)最终 mysql value = 10;redis value = 9
解决方案:
1、延时双删除
场景:A进程update set value = 10 where value = 9 ;B进程查询value;
1)A 进程先删除缓存 还没来得及修改数据或者事务未提交
2)B 进程开始查询,没有命中缓存,所以查库并写入缓存 redis value = 9
3)A 进程更新数据库完成 mysql value = 10
4)A 进程估算延时时间,sleep之后再次删除缓存
5)最终mysql value = 10;redis value 为空(下次查询直接查库)
6)延时的原因时防止B进程在A进程更新完之后B进程还没来得及写入缓存
2、请求串行化
1)创建两个队列 :更新队列和查询队列
2)当缓存不存在需要查库的时候将key存入更新队列
3)如果查询未完成之前有新的请求进来,并且发现更新队列中还存在key则将key放入查询队列,则等待;不存在则重复第二步
4)如果查询的数据发现查询队列已经存在则不需要再次写入队列
5)数据更新完成之后rpop更新队列,同时rpop查询队列,释放查询请求
6)查询请求可以使用while + sleep 查询缓存并且设置最大延迟时间,还没有完成则返回空