redis、db数据一致性思考
常见的以下方案:
1、先更新db,再删redis ,读数据先读redis,没有的话读db并写入redis
存在的问题q1:假若删redis失败,那么一直读到的是脏数据
补充说明:删失败可以加重试
高并发读、写场景下存在的问题q2:
写线程a | 写线程b | 读线程c | |
---|---|---|---|
t1 | 更新db=2 | ||
t2 | 删redis | ||
t3 | 读redis没有,查db=2 | ||
t4 | 更新db=3 | ||
t5 | 删redis | ||
t6 | 写入redis 2 | ||
t7 |
备注:一般redis数据删除不会有问题的q1问题几乎不用考虑。q2问题是重点
2、延时双删:先删redis ,再更新db,加延时再删redis
双删的其中一个目的是为了减轻q1的问题
延时双删只能缓解q2的问题,但不能100%解决,如下:
假若当前db中数据为1
线程a写 | 线程b读 | |
---|---|---|
t1 | 删redis | |
t2 | 读redis没有,查db=1 | |
t3 | 更新db=2 | |
t4 | 把db=1写入redis | |
t5 | 延迟短暂时间删redis |
延时双删的话,可以根据 读线程查询db并更新redis的总时间设置延时时间(也还不能保证100%不出现q2类的问题)
延时删除可以采用mq异步去删除,这样就不会阻塞写线程。
3、db日志解析
如通过解析binlog日志,异步更新缓存数据
在上述前2种方案中,可以应对大部分场景。极端场景下q2的问题还是存在的。如果对数据一致性要求很高的话,要彻底避免,加分布式锁是可以的,但对性能有影响
如果对一致性要求不高的情况,定时删除或者用上述2中方案都可以