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读写分离的主从延时时间。
采用这种同步淘汰策略,吞吐量降低怎么办?
异步删除。
删缓存失败了怎么办:重试机制
因为第二次删除缓存是异步执行,如果失败了,不影响之前的请求。
一 : 采用消息队列
造成代码侵入
二: bingo