登录

redis 缓存和 mysql 数据一致性

php
0 1473
1、先更新redis 再更新数据库

 场景: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 查询缓存并且设置最大延迟时间,还没有完成则返回空

发表评论

0 个回复