Redis缓存一致性问题(自用记录)

背景

在开发过程中,redis缓存技术被大范围应用。由于现在的系统大多是分布式的,高并发的,redis和传统的数据库,存在数据不一致的问题。

解决方案

本文主要探讨两者数据不一致的解决方案:

  1. 给缓存设置过期时间,保证数据的最终一致性
    我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力。
    也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。

  2. 通过合理的更新策略保证数据一致性

 - 先更新数据库,再更新缓存
 -  先删除缓存,再更新数据库
 -  先删除缓存,再更新数据库

方案的可实施性

1.给缓存设置过期时间,保证数据的最终一致性。
这种方案虽然能保证数据的一致性,但是在一定时间范围内数据存在不一致性

2 更新策略分析
2.1 先更新数据库,再更新缓存。这种方案看似可行,实际并不可靠。原因如下:

同时有请求A和请求B进行更新操作,那么会出现

1)线程A更新了数据库
2)线程B更新了数据库
3)线程B更新了缓存
4)线程A更新了缓存

这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络,运算等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。

2.2 先删除缓存,再更新数据库。这种方案也极易导致数据不一致。

如下操作

1)请求A进行写操作,删除缓存
2)请求B查询发现缓存不存在
3)请求B去数据库查询得到旧值
4)请求B将旧值写入缓存
5)请求A将新值写入数据库

上述情况就会导致不一致的情形出现。而且,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。

如何解决解决这种问题,采用延时双删技术

1)先淘汰缓存
2)再写数据库(这两步和原来一样)
3)休眠1秒,再次淘汰缓存

有效的将1秒内所造成的缓存脏数据,再次删除。

2.3 先更新数据库,再删除缓存。这种方案是可行性比较高的方案,但也不是绝对的可靠。
两个线程同时进行写操作:

1) 线程A更新数据库
2)线程B更新数据库
3)线程B删除缓存
4)线程A删除缓存

这种情况下不存在问题。但是也存在概率比较低可靠性问题:

1)缓存刚好失效
2)请求A查询数据库,得一个旧值
3)请求B将新值写入数据库
4)请求B删除缓存
5)请求A将查到的旧值写入缓存

这种情况下也会存在脏数据的问题。

为什么这种情况概率比较低?

  1. 这个条件需要发生在读缓存时缓存失效,而且并发着有一个写操作。
  2. 而实际上数据库的写操作会比读操作慢得多,而且还要锁表,而读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存,所有的这些条件都具备的概率基本并不大。

那么如何解决?
可以采用延时双删除。

1)更新数据库
2)删除缓存
3)延时几秒再次删除缓存

你可能感兴趣的:(Redis,缓存,redis,数据库)