并发线程读取Redis和数据库的一致性问题

并发线程读取Redis和数据库一致性问题

一致性问题出现背景

当数据发生update和delete时,需要同时更新Redis和数据库,我们先改数据库再删缓存。但这两个写操作不满足原子性,任一操作失败都会导致两者数据的不一致。我们先写数据库落盘,再将删除缓存操作放入消息队列中,多次重试删除缓存来保证两个操作均被执行。这样在新的访问到达时会直接访问数据库,读取最新数据并重新缓存入Redis

操作顺序\数据值 数据库 缓存值
1.写数据库成功 x=old —> x=new x=old
2.加入消息队列 x=new x=old
3.消费删缓存失败 x=new x=old
4.消费删缓存成功 x=new delete x
5.若多次失败则告警人工解决 x=new delete x
6.新访问到达读取缓存 x=new 无缓存,重新load
7.访问结束 x=new x=new

为什么会并发不一致

由于这两个操作不满足原子性,导致写数据库成功后、删除缓存旧值之前,新来的读线程会读到缓存中的旧数据

线程A 线程B 线程C 线程D
写数据库x=new
读取缓存中的旧数据x=old
删除缓存x=old
读缓存未命中重新load,改读数据库x=new
缓存命中x=new

实现一致性解决方案

强一致性方案

使用锁保证数据库写和缓存写的原子性,可确保强一致性,但是在高并发场景中会牺牲性能,适用于数据严格要求一致性的场景

最终一致性

上述并发不一致的场景中,由于删缓存速度较快,仅会出现短暂不一致,后续进入的线程均读到最新数据,适合允许数据出现短暂不一致的场景

参考资料

极客时间 | 缓存异常(上):如何解决缓存和数据库的数据不一致问题?

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

©2018-2025 Howell版权所有 备案号:冀ICP备19000576号