2021-03-07
今天看到一个有意思的问题,如何保证缓存和数据库的一致性,思考后查资料总结如下。
要对数据库更新,如何处置缓存,更新or删除?
选择删除缓存。
因为要更新的数据可能是简单的也可能是复杂的,复杂的数据更新缓存的话,成本较大,所以选择删除缓存。
如果选择更新缓存的话,频繁的写操作意味着数据库和缓存都频繁更新,但重点是,该数据的读频率多大。根据28法则,20%的数据占了80%的访问量,对于某些缓存的频繁更新有点得不偿失。
先淘汰缓存还是先更新数据库?
先淘汰缓存
如果先更新数据库,再淘汰缓存,数据库更新完了之后,若缓存淘汰失败,那么后面读到的都是脏数据了,直到缓存失效。
如果先淘汰缓存,再更新数据库,如果数据库更新失败,只会造成一次缓存miss。相较而言,后者对业务的影响较小。
高并发下数据不一致问题的分析与解决
如下场景:同时有一个请求A进行更新操作,另一个请求B进行查询操作
(1)请求A进行写操作,删除缓存
(2)请求B发现缓存不存在
(3)请求B去数据库查询得到旧值
(4)请求B将查到的旧值写入缓存
(5)请求A将新值写入数据库
这样就出现了数据不一致的错误,导致脏读。
只有在对数据进行并发读写时,才会出现这样的问题。
其实并发量很低,特别是读很低,每天就1w的访问量,那么很少会出现上面的状况。
但问题是,如果每天的是上亿的流量,每秒并发读是几万,每秒只要有数据更新的请求,就可能会出现上述的数据库+缓存不一致的情况。
高并发了以后,问题是很多的。
解决方法
- 延时双删策略
在对数据写操作之前,删除缓存,延时1s后再将缓存删除。这样做可以将1s内的缓存脏数据清除。时间间隔可以根据具体业务设定。 - 读请求和写请求串行化
将读请求和写请求串行化,串到一个内存队列中去,这样就可以保证一定不会出现不一致的情况。
串行化之后,会导致系统的吞吐量大幅度降低,用比正常情况下多几倍的机器去支撑线上的一个请求。
一般来说,如果系统不是严格要求缓存+数据库必须一致性的话,缓存可以稍微的跟数据库偶尔有不一致的情况,最好不要做这个方案。