如何保证redis与数据库的数据一致性

唯有代码不会骗人 唯有代码不会骗人     2023-03-05     117

关键词:

首先,分为两种场景:

一. 针对读场景:

(1) A请求查询数据,如果命中缓存,那么直接取缓存数据返回即可。如果请求中不存在,数据库中存在,那么直接取数据库数据返回,然后将数据同步到Redis中。不会存在数据不一致的情况。
(2) 在高并发的情况下,A请求和B请求一起访问某条数据,如果缓存中数据存在,直接返回即可,如果不存在,直接取数据库数据返回即可。无论A请求B请求谁先谁后,本质上没有对数据进行修改,数据本身没变,只是从缓存中取还是从数据库中取的问题,因此不会存在数据不一致的情况。

因此,单独的读场景是不会造成Redis与数据库缓存不一致的情况,因此我们不用关心这种情况。

二. 针对写场景:

(1) 如果该数据在缓存中不存在,那么直接修改数据库中的数据即可,不会存在数据不一致的情况。
(2) 如果该数据在缓存中和数据库中都存在,那么就需要既修改缓存中的数据又修改数据库中的数据,而且在高并发的场景下,还存在修后关系,这就会导致数据不一致的问题。

针对(2)的情况有两个疑问:

(1)是删除缓存数据,等待下次查询该数据时,缓存中没有直接去数据库中查询,同时添加到缓存中,还是更新缓存呢?
(2)更新缓存中的数据,是先更新缓存还是先更新数据库呢?

关于疑问(1)有两个方案

方案1:删除缓存

优点:实现简单,不需要再更新数据库操作时在进行更新数据逻辑,直接删除对应缓存的key即可。
缺点:由于缓存被删除,下次查询无法命中缓存,需要在查询后将数据写入缓存,增加查询逻辑。同时在高并发的情况下,同一时间大量请求访问该条数据,第一条查询请求还未完成写入缓存操作时,这种情况,大量查询请求都会打到数据库,加大数据库压力。

方案2:更新缓存

优点:缓存命中率高,只要缓存进行了更新,后续的读请求就不会出现缓存未命中的情况。
缺点:在某些业务场景下,更新数据的成本较大,并不是单纯将数据的数据查询出来丢到缓存中即可,而是需要连接很多张表组装对应数据存入缓存中,并且可能存在更新后,该数据并不会被使用到的情况。

综合分析

在一般的业务中一般都采用缓存淘汰这种方案,而非缓存更新。因为:

  • 大多数情况下,redis缓存中的数据并不是完全复制数据库中的数据,而是将db中多张表的数据进行了重新计算,筛选后更新到redis。如果在db某一张表的数据发生了变化的情况下,需要同步重新计算redis中值的话,更新成本过高。
  • 缓存更新后的新值,无法保证一定会有读请求命中,如果一直没有请求命中该部分冷数据,其实是产生了一定的资源浪费(计算成本+存储成本)。
  • 相较于删除缓存方案来说,仅有一次读请求cache miss的结果来说,淘汰缓存策略的缺点完全可以容忍。

比如,A表中的字段,1分钟更改了100次,如果采用更新缓存策略,则需要计算100次,哪怕1分钟内只有1次读请求;如果采用淘汰缓存策略,如果1分钟内只有1次请求,则只需要计算1次即可,开销大幅度降低。

关于疑问(2)有两个方案

方案1:先更新缓存,后更新数据库

正常情况

(1)A请求进行写操作,先淘汰缓存,再更新数据库
(2)B请求进行读操作,由于A请求已将缓存淘汰,B请求没有在redis中发现所需数据,因此从数据库中读取数据,并更新缓存到redis中

异常情况1

(1)A请求进行写操作,先淘汰缓存
(2)B请求进行读操作,由于A请求已将缓存淘汰,B请求没有在redis中发现所需数据,因此从数据库中读取数据,并更新缓存到redis中。注意,此时redis中被更新的依然是老数据,A请求的数据库更新操作尚未完成
(3)A请求进行数据库更新操作。此时,数据库中是新数据,redis缓存中是老数据,产生了数据不一致的问题。且该不一致会一直持续到缓存自然失效或者下次的更新操作

对于该种异常情况,提供两种解决思路:

1.异步更新缓存

(1)A请求进行写操作,先淘汰缓存
(2)B请求进行读操作,由于A请求已将缓存淘汰,B请求没有在redis中发现所需数据,因此从数据库中读取数据。注意,此时不向redis写入新的缓存策略
(3)A请求通过订阅数据库binlog,对redis缓存数据进行异步更新

该方案虽然解决了数据不一致的问题,但是在数据库更新操作完成前,所有的读请求都会直接打到数据库上,具有比较大的风险。

2.延时双删

(1)A请求进行写操作,先淘汰缓存
(2)B请求进行读操作,由于A请求已将缓存淘汰,B请求没有在redis中发现所需数据,因此从数据库中读取数据,并更新缓存到redis中。注意,此时redis中被更新的依然是老数据,A请求的数据库更新操作尚未完成。假设该步骤耗时N秒
(3)A请求进行数据库更新操作。
(4)由于此时redis中写入了老数据,因此A请求在休眠M秒后(M略大于N),再次对redis进行淘汰缓存操作

该方案虽然解决了数据不一致的问题,但是由于请求A在更新完数据库之后,需要休眠M秒再次淘汰缓存,一定程度上影响了数据更新操作的吞吐量。可以尝试将等待M秒更新redis的操作放到另一个单独的线程(比如消息队列 + 重试机制)。可以有效缓解吞吐量降低的问题。

异常情况2

(1)A请求进行读操作,此时redis缓存中没有数据,因此直接从数据库中读取数据
(2)B请求进行写操作,先淘汰缓存,再更新数据库
(3)A请求进行将从数据库中读到的老数据,更新到redis。此时产生数据不一致问题。

该种异常情况发生概率极低,一般读操作比写操作要快。如有担心,可以采用上述的延时删除策略

方案2: 先更新数据库,后更新缓存

正常情况

(1)A请求进行写操作,先更新数据库,再淘汰缓存
(2)B请求进行读操作,由于A请求已将缓存淘汰,B请求没有在redis中发现所需数据,因此从数据库中读取数据,并更新缓存到redis中

异常情况1

(1)A请求进行写操作,先更新数据库
(2)B请求进行读操作,由于A请求尚未淘汰缓存,B请求在redis中发现所需数据,因此直接返回老数据,产生了数据不一致的问题
(3)A请求淘汰缓存。
(4)C请求进行读操作,发现redis中没有数据,因此从数据库中读取新数据,并更新至缓存。数据不一致的问题解决。

该场景下,数据最终一致,只是在高并发下产生了一小段时间的数据不一致。

异常情况2

(1)A请求进行读操作,此时redis缓存中没有数据,因此直接从数据库中读取数据
(2)B请求进行写操作,更新数据库,并将redis中缓存进行了淘汰(虽然此时redis中并没有任何的缓存)
(3)A请求将从数据库中读到的老数据,更新到redis。此时产生数据不一致问题。

该种异常情况发生概率极低,一般读操作比写操作要快。如有担心,可以采用上述的延时删除策略。

总结

方案1:先淘汰缓存,后更新数据库的策略,有可能导致长时间的数据不一致问题,可以通过延时双删 or 异步更新缓存策略进行解决。
方案2:先更新数据库,后更新缓存,有可能导致极短时间内的数据不一致,但是数据最终是一致的。

分布式系统——并发条件下如何保证缓存与db数据一致性

...一致性指的是在程序运行过程中本地缓存、分布式缓存、数据库三者之间的数据一致性常见的本地缓存有hashmap、currenthashmap、guavacache、caffeine分布式缓存常见的有redis、memcache常见数据不一致常见有:本地缓存与mysql不一致redis缓... 查看详情

如何保证数据库与redis缓存数据一致性(代码片段)

...解为啥会出现数据不一致呢?根本原因是我们无法将数据库更新操作与缓存更新操作放在同一个事务内同步成功,同步失败!一、常见操作及问题1.1、先更新数据库,后更新缓存    问题:假如有两个请求&#x... 查看详情

美团二面:redis与mysql双写一致性如何保证?(代码片段)

...ySQL双写一致性如何保证?这道题其实就是在问缓存和数据库在双写场景下,一致性是如何保证的?本文将跟大家一起来探讨如何回答这个问题。公众号:捡田螺的小男孩谈谈一致性一致性就是数据保持一致,... 查看详情

如何保证redis与数据库的数据一致性

...;那么直接取缓存数据返回即可。如果请求中不存在,数据库中存在,那么直接取数据库数据返回,然后将数据同步到Redis中。不会存在数据不一致的情况。(2)在高并发的情况下,A请求和B请求一起访问某... 查看详情

redis缓存如何保证一致性

...,速度快单线程模型,避免线程切换带来的开销,速度快一致性问题  读数据的时候首先去Redis里读,没有读到再去MySQL里读,读回来之后更新到Redis里作为下一次的缓存。写数据的时候回产生数据不一致的问题,无论是先写到... 查看详情

mysql和redis数据如何保持一致

先阐明一下Mysql和Redis的关系:Mysql是数据库,用来持久化数据,一定程度上保证数据的可靠性;Redis是用来当缓存,用来提升数据访问的性能。关于如何保证Mysql和Redis中的数据一致(即缓存一致性问题),这是一个非常经典的问... 查看详情

redis11_缓存和数据库一致性如何保证解决方案提供canel解决数据一致性问题

文章目录①.缓存和数据库双写一致保证②.缓存数据一致性-解决方案③.缓存数据一致性-解决-Canal①.缓存和数据库双写一致保证①.只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问... 查看详情

如何保证mysql和redis的数据一致性?10张图带你搞定!

...”一般指的是:缓存中有数据,缓存的数据值=数据库中的值。但根据缓存中是有数据为依据ÿ 查看详情

如何保证数据库与redis缓存数据一致性(代码片段)

...解为啥会出现数据不一致呢?根本原因是我们无法将数据库更新操作与缓存更新操作放在同一个事务内同步成功,同步失败!一、常见操作及问题1.1、先更新数据库,后更新缓存    问题:假如有两个请求&#x... 查看详情

java进阶面试必问:如何保证缓存与数据库的双写一致性?

面试题如何保证缓存与数据库的双写一致性?面试官心理分析你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?面试题剖析一般来说,如果允... 查看详情

场景应用:如何保证缓存与数据库的双写一致性?

文章目录如何保证缓存与数据库的双写一致性?四种同步策略:同步策略探究更新缓存还是删除缓存:先操作数据库还是缓存:最终结论:补充:延时双删策略采用读写分离的架构怎么办?第二次删除... 查看详情

redis与mysql双写一致性(代码片段)

双写一致性时为了保证Redis缓存与MySQL数据库中的数据一样我们对Redis中没有的数据,MySQL怎么回写呢?我们用双检加锁策略这样只要第一个请求发过来,后面的请求就不会发送到MySQL,直接从Redis中获取缓存数据就可以了。 为... 查看详情

如何保证缓存与数据库的双写一致性?

一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库”必须保持一致性的话,最好不要做这个方案,即:读请求和写请求串行化,串到一个内存队列里... 查看详情

大厂面试01期高并发场景下,如何保证缓存与数据库一致性?

面试题:高并发场景下,如何保证缓存与数据库一致性?问题分析我们日常开发中,对于缓存用的最多的场景就像下图一样,可能仅仅是对数据进行缓存,减轻数据库压力,缩短接口响应时间。这种方案在不需要考虑高并发得去... 查看详情

数据库与缓存一致性问题解决方案

...广泛用在缓存场景,一是能提高业务系统的性能,二是为数据库抵挡了高并发的流量请求。把Redis作为缓存组件,需要防止出现以下的一些问题,否则可能会造成生产事故。Redis缓存满了怎么办?缓存穿透、缓存击穿、缓存雪崩... 查看详情

java面试常被问到这道题:如何保证缓存与数据库的双写一致性?

面试原题如何保证缓存与数据库的双写一致性?面试官心理分析你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?面试题剖析一般来说,如果... 查看详情

text保证redis的主从数据库数据一致性的方法(代码片段)

查看详情

otpub知识课堂:如何保证混合云备份与灾难恢复的数据一致性

...据也必须进行同步;这么做有助于IT技术团队保证数据的一致性,理想的结果是,如果混合云平台出现问题,处理速度只会变慢,然后可以自动恢复,因为平台的其他部分可以承担负载,或者在公共云的情况下,随着工作负载迁... 查看详情