一、什么是一致性问题为了提升服务的性能,我们一般会把热点放进缓存,那么这些热点数据就同时存在于数据库和缓存中,缓存中的数据和数据库中的数据要保持一致,这便是缓存一致性问题。 二、使用缓存存在的问题加了缓存之后,读写流程大概如下: 1. 读流程 2. 写流程 3. 写操作的应该更新缓存还是删除缓存 答案是应该删除缓存,如果是更新,可能会有如下问题: 如上图所示,如果线程 A 先更新了 DB,接着线程 B 更新 DB,正常情况,缓存中保存的应该是线程 B 写入 DB 的数据,但因为最后是线程 A 去更新的缓存,因此导致 DB 和缓存中的数据不一致。 4. 既然要用删除,删除操作在更新DB之前还是之后呢 答案是之前,如果是之后,可能会出现如下问题: 如果先更新 DB,在更新了 DB 之后,还没来得及删除缓存之前,线程 B 读请求进来了,那么读取到的是缓存中的旧数据,也会出现一致性问题。 5. 先删除再操作DB就没问题吗 答案是也会有问题,可能会出现如下场景: 线程 A 先删除了缓存,还没来得及更新 DB 的时候,线程 B 进来了,把 DB 中的旧数据又读取到了缓存中,最后线程 A 更新了 DB,数据还是不一致。 三、缓存一致性问题的解决方案1. 双删延迟策略 上面说了先删除缓存还是会存在问题,就是线程 A 更新 DB 之前如果线程 B 把数据读到缓存中了,数据也会不一致。双删延迟策略就是更新了 DB 后休眠一段时间再次删除缓存,如下:
2. 使用binlog异步删除缓存 我们知道,DB 的操作一般都会记录到日志中,比如 MySQL,所有的写操作都会记录到 binlog 中,那么我们可以通过 binlog,去删除缓存。canal 就是一款用来解析数据库日志的工具,我们可以接入 canal,采集到日志,然后通过 MQ 异步的去删除缓存,这样对业务代码就没有入侵了。异步删除缓存流程如下:
|
|