分布式缓存一致性问题

448 阅读3分钟

1 为什么不是更新,而是删除

2 先操作缓存,再操作数据库。

3 如果要保证强一致性,怎么办?

为什么使用缓存

缓存量大且不经常变化的数据,适合缓存。

可以提高系统的吞吐量,缩短响应时间。减轻数据库的压力。

额外的问题:

本地缓存/分布式缓存?

分布式缓存增加系统复杂性?

一致性问题?

如何保证缓存和数据库一致性

为什么不是更新,而是删除缓存?

原因一:线程安全角度

同时有请求 A 和请求 B 进行更新操作,那么会出现

(1)线程 A 更新了数据库

(2)线程 B 更新了数据库

(3)线程 B 更新了缓存

(4)线程 A 更新了缓存

这就出现请求 A 更新缓存应该比请求 B 更新缓存早才对,但是因为网络等原因,B 却比 A 更早更新了缓存。这就导致了脏数据,因此不考虑。

原因二:业务场景角度

有如下两点:

(1)如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。

(2)如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合。

先操作缓存,还是先操作数据库?

一 不考虑并发请求的场景下《58 沈剑架构系列】缓存架构设计细节二三事》

对于不能确保事务性的操作,一定涉及到“哪个任务线做,哪个任务后做”的问题。

解决办法就是:如果出现不一致性,谁先做对业务的影响较小,就谁先执行。

如果先更新数据库成功,删除缓存失败,那么就会读取到脏数据,影响很大!

如果先删除缓存成功,更新数据库失败,那么只会引起一次缓存数据缺失,几乎无影响!

二 考虑并发请求的场景下《分布式之数据库和缓存双写一致性方案解析》

先删除缓存,再更新数据库

会导致数据不一致

请求A查询,请求B更新,请求B删除缓存,请求A读取到脏数据,写入缓存,请求B写入数据库。

先更新数据库,再删除缓存

请求A查询,请求B更新,请求A查询得到一个脏数据,请求B更新数据库,请求B删除缓存,请求A写入缓存。

这样,概率比1更小。

如果想实现基础的一致性,那么就先更新数据库,再删除缓存。

如果需要强一致性怎么办?

只能做到最终一致性。CAP理论。

缓存延时双删

1)先淘汰缓存

(2)再写数据库(这两步和原来一样)

(3)休眠 1 秒,再次淘汰缓存

这么做,可以将 1 秒内所造成的缓存脏数据,再次删除。

1s是怎么确定的呢?

是在读取到之后到写缓存之间的逻辑处理时间,以及mysql读写分离的主从延时时间。

采用这种同步淘汰策略,吞吐量降低怎么办?

异步删除。

删缓存失败了怎么办:重试机制

因为第二次删除缓存是异步执行,如果失败了,不影响之前的请求。

一 : 采用消息队列

造成代码侵入

image.png

二: bingo

image.png