高并发下如何解决redis缓存和数据库不一致的问题-缓存文件写入失败

现在的web架构一般都用redis作为缓存层来减轻数据库的压力,数据在此架构下的读取问题,一般都是先判断redis缓存是否有数据,如果有,直接返回,否则读取数据库的数据,写入redis,返回数据,这是大致的读取流程。

高并发下如何解决redis缓存和数据库不一致的问题

那么为什么会出现redis和数据库不一致的问题呢?举个例子,如果你的缓存里现在缓存了用户的年龄的数据,每次用户访问的时候,如果缓存里有这个数据,直接返回,那么如果用户更新了自己的年龄,你的操作步骤是什么?

  • 先更新(删除)redis缓存,再更新数据库
  • 先更新数据库,再更新(删除)用户缓存

上面两种不同的操作顺序,不论哪种方法,理论上如果两个步骤都成功了,那没问题,如果一个更新成功了,另一个更新失败了,那么就会导致数据库和缓存不一致的问题,这就要求操作必须具备原子性,不论谁先执行,只要一个步骤出现错误,就因该回滚,谁都不能成功。

更新缓存or删除缓存

这里简单说下,更新缓存可能要消耗更多的cpu资源,所以建议直接删除缓存。

举个例子:缓存money=100,数据库money=100,现在要求money=99

下面讨论并发下两种策略可能带来的问题

先删除缓存成功,后更新数据库失败

  • 线程A删除缓存,更新数据库money中,还没更新完
  • 线程B过来发现缓存没有了,去数据库读取,读到的money=100
  • 线程B,将读到的money=100写入缓存,现在缓存中的money=100
  • 线程A将数据库的money更新完成,money=99
  • 最终redis缓存的数据是100,数据库是99
  • 适合原子性要求高的,不适合高并发

造成这个问题的原因就是线程A还没干完事情,线程B就插进来了。解决这个问题的办法,就是串行化,让操作顺序执行,不能交替进行。顺序应该是删除、更新、读取。

高并发下如何解决redis缓存和数据库不一致的问题

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

  • 线程A过来查数据,缓存没有数据,读取数据库money=100
  • 线程B更新数据库money=99,并删除缓存
  • 线程A把读到的money=100,写到缓存里
  • 最终redis缓存是100,数据库是99
  • 适合高并发,不适合原子性高的

造成这个问题的原因就是第二步骤,其实缓存并不存在,删除是没有用的,应该等到A把缓存写入之后,再尝试删除缓存,这时候建议再第二步骤一直尝试删除缓存,知道删除成功。

高并发下如何解决redis缓存和数据库不一致的问题

欢迎关注,坚持更新

推荐阅读