redis 缓存的模式
一:读
1:缓存边缘化(cache aside)
应用程序先读取缓存,如果缓存没有,再去读数据库,然后更新缓存
2:通读(Read-through)
在上面的基础上抽象一层缓存层,让缓存层去读缓存数据库
二:写
1:通写(Write-through)
2:缓存之后在去写数据库(适合写数据频繁的操作)
三:更新
1:先跟新数据库。再更新缓存,最大问题两个并发的写操作会导致脏数据
如下图(以Redis和Mysql为例),两个并发更新操作,数据库先更新的反而后更新缓存,数据库后更新的反而先更新缓存。这样就会造成数据库和缓存中的数据不一致,应用程序中读取的都是脏数据。
2:先删除数据库。再更新缓存。 逻辑错误,两个读和写的操作导致脏数据
如下图(以Redis和Mysql为例)。假设更新操作先删除了缓存,此时正好有一个并发的读操作,没有命中缓存后从数据库中取出老数据并且更新回缓存,这个时候更新操作也完成了数据库更新。此时,数据库和缓存中的数据不一致,应用程序中读取的都是原来的数据(脏数据)。
3:先更新缓存。再删除数据库。推荐使用这种方法。
但是这种方式理论上还是可能存在问题。如下图(以Redis和Mysql为例),查询操作没有命中缓存,然后查询出数据库的老数据。此时有一个并发的更新操作,更新操作在读操作之后更新了数据库中的数据并且删除了缓存中的数据。然而读操作将从数据库中读取出的老数据更新回了缓存。这样就会造成数据库和缓存中的数据不一致,应用程序中读取的都是原来的数据(脏数据)。
但是,仔细想一想,这种并发的概率极低。因为这个条件需要发生在读缓存时缓存失效,而且有一个并发的写操作。实际上数据库的写操作会比读操作慢得多,而且还要加锁,而读操作必需在写操作前进入数据库操作,又要晚于写操作更新缓存,所有这些条件都具备的概率并不大。但是为了避免这种极端情况造成脏数据所产生的影响,我们还是要为缓存设置过期时间。