Redis 缓存数据一致性

本文将介绍 Redis 作为缓存时的数据一致性问题及其解决方案。

一、缓存数据一致性问题

一旦在应用中引入了缓存,同一份数据便会在数据库和缓存同时存储,如果因为 “增删改” 导致两个地方的数据不一致,便会影响整个应用的数据正确性。

二、数据不一致的产生

1. 读写缓存 - 同步直写

对于同步直写策略,数据更新时需要同时更新缓存和数据库,一般会引入事务机制以确保操作原子性。因此,可以认为缓存和数据库的数据是一致的。

2. 读写缓存 - 异步写回

对于异步写回策略,假如在数据库还未写回时,缓存发生故障,数据库将丢失这一部分改动。因此,无法保证数据一致性。

3. 只读缓存

(1) 原子性操作带来的数据不一致

对于只读缓存而言,数据更新时需要同时进行 “删除缓存值” 和 “更新数据库值” 两个子操作,无论子操作的顺序如何,只要无法保证原子性,便会导致数据不一致。

当然,上图中的情况没有讨论的必要,操作失败了本就应该重试。

一种容易想到的解决方案是:多次重试,直至成功。

(2) 并发请求带来的数据不一致

  • 假设子操作的顺序是:先删除缓存值,后更新数据库。

    更新数据库需要一定的时间,在 “缓存值删除且数据库未被更新” 期间,如果有另一请求访问该数据,则它会从数据库中获取旧数据并更新缓存,导致数据不一致。

    一种解决方案是:在更新完数据库后,等待一小段时间,再进行一次缓存删除操作。这种做法先删除一次缓存,延迟一段时间后又删除一次缓存,因此被称为 延迟双删

    等待的时间是为了确保 “缓存值删除且数据库未被更新” 期间的其它请求已执行完成,避免删除后又被错误更新

  • 假设子操作的顺序是:先更新数据库,后删除缓存值。

    在这种情况下,数据更新期间会有一部分请求从缓存中读取到旧数据,不过对业务的影响较小。

四、建议做法

建议将 Redis 作为只读缓存,并且先更新数据库后删除缓存。

参考