Good, better, best. Never let it rest.

缓存和数据库双写一致性问题

🎭 使用Redis缓存,就会遇到缓存和数据库双写一致性问题。

根据是否接收写请求,我们可以把缓存分成读写缓存和只读缓存。

## 读写缓存

读写缓存指读请求、写请求都会发到缓存处理。在使用读写缓存时,最新的数据是在Redis中,而Redis是内存数据库,一旦出现掉电或宕机,内存中的数据就会丢失。

### 一致性方案

写缓存时,也同步写数据库,缓存和数据库中的数据一致;在业务应用中采用事务机制,来保证缓存和数据库的更新具有原子性。

## 只读缓存

只读缓存指读请求会先经过Redis,写操作不会经过Redis,但是会删除相应的数据。当再次读取数据时,会发生缓存缺失,然后从数据库中读取并写入缓存。

### 一致性方案

只读缓存比较复杂,用一张表进行总结:

延迟双删:在线程 A 更新完数据库值以后,我们可以让它先 sleep 一小段时间,等线程 B、C 先从数据库读取数据,再把缺失的数据写入缓存,然后,线程 A 再进行删除。

伪代码:

1
2
3
4
redis.delKey(X)
db.update(X)
Thread.sleep(N)
redis.delKey(X)

### 小结

对比可知,先更新数据库再删除缓存的方法较好。

原因有二:

  • 如果先删除缓存值再更新数据库,有可能导致请求因缓存缺失而访问数据库,给数据库带来压力。
  • 延时双删中的等待时间不好估算。

实际操作中,我们更新数据库时,先在 Redis 缓存客户端暂存并发读请求,等数据库更新完、缓存值删除后,再读取数据,就保证了数据的全部一致性。