扫码关注公众号

Redis和MO中间件之Redis数据一致性
06-20
151观看
01

Redis如何与数据库保持双写一致性

 保证缓存和数据库的双写一致性,共有四种同步策略,即先更新缓存再更新数据库、先更新数据库再更新缓存、先删除缓存再更新数据库、先更新数据库再删除缓存。 先更新缓存的优点是每次数据变化时都能及时地更新缓存,这样不容易出现查询未命中的情况,但这种操作的消耗很大,如果数据需要经过复杂的计算再写入缓存的话,频繁的更新缓存会影响到服务器的性能。如果是写入数据比较频繁的场景,可能会导致频繁的更新缓存却没有业务来读取该数据。 删除缓存的优点是操作简单,无论更新的操作复杂与否,都是直接删除缓存中的数据。这种做法的缺点则是,当删除了缓存之后,下一次查询容易出现未命中的情况,那么这时就需要再次读取数据库。那么对比而言,删除缓存无疑是更好的选择。 那么我们再来看一下先操作数据库和后操作数据库的区别;先删除缓存再操作数据库的话,如果第二步骤失败可能导致缓存和数据库得到相同的旧数据。先操作数据库但删除缓存失败的话则会导致缓存和数据库得到的结果不一致。出现上述问题的时候,我们一般采用重试机制解决,而为了避免重试机制影响主要业务的执行,一般建议重试机制采用异步的方式执行。当我们采用重试机制之后由于存在并发,先删除缓存依然可能存在缓存中存储了旧的数据,而数据库中存储了新的数据,二者数据不一致的情况。 所以我们得到结论:先更新数据库、再删除缓存是影响更小的方案。如果第二步出现失败的情况,则可以采用重试机制解决问题。

来自:redis-redis
02

如何保证Redis与数据库的数据一致

1、先删除“缓存”再去更新“数据库”。但是该方案还存在问题:在高并发情况下,第一个线程删除缓存,还没来得及去操作数据库,这时第二个线程访问缓存,发现为null,于是去数据库查询,获取到需要的值,这时候第一个线程才开始操作数据库,然后设置缓存,但是第二个线程又跟奇怪的将第一个线程刚设置的缓存给覆盖掉,然后就出现“乌龙”,数据不一致的问题也出现了!解决方案:①先操作缓存去修改数据库,但不删除缓存。将这个不删除的缓存设置为一个特殊值(*123),当客户端读缓存的时候,发现有前缀包含(*???),知道他是坏值,就会进行休眠(1秒这样),然后再去查询Redis。//这样做的弊端是:特殊值对业务可能出现影响,休眠时间会重复(高并发情况下,修改操作频繁,反复会修改这个特殊值的内容,然后同时出现睡眠),影响性能。②延迟双删,先删除缓存数据,再把数据更新到数据库中,休眠一会(根据业务逻辑的耗时,更改休眠时间)后再次删除该缓存数据。若线程1是更新请求,线程2是查询请求,延迟双删,可以保证再这两个请求同时存在的情况下的数据一致性!确保查询请求结束,更新请求可以删除查询请求造成的缓存脏数据。总结:写操作不能太频繁!2、先删除“数据库”再去更新“缓存”。该案例的问题是:数据库写完之后,再删除缓存,但删除失败了,这会导致数据不一致。解决方案:①给缓存设置一个过期时间,但缺点是,过期时间内不能保证数据是有用的数据,可能是上次没删掉的坏数据。②引入MQ,保证原子操作。一个去删缓存,一个去操作数据库。MQ若是删除操作失败了,启动MQ重试机制,在重试的这段时间,缓存数据不会更新。③将热点数据缓存设置为永不过期,但是在value当中写入一个逻辑上的过期时间,另外起一个后台线程,扫描这些key,对于已逻辑上过期的缓存,进行删除。总结:始终只能保证一定时间内的最终一致性。3、Redis和Mysql集群实现的读写分离架构如果MySQL采用的是读写分离的架构,主从服务器之间也会存在时间差,也就是A更新操作,删除缓存,并请求主数据库进行数据更新,主库与从库进行同步数据的操作,B进行查询操作时,缓存中没有数据,就去从库中读取数据,此时主从数据未更新完成,拿到的还是旧数据。解决方法是:查询数据经过Redis时,若查询缓存为空时,强制将其指向主数据库中进行查询。4、异步更新缓存(基于订阅binlog的同步机制)MySQLbinlog增量订阅消费+消息队列+增量数据更新到redis读Redis:热数据基本都在Redis写MySQL:增删改都是操作MySQL更新Redis数据:MySQ的数据操作binlog,来更新到RedisRedis更新①数据操作主要分为两大块:一个是全量(将全部数据一次写入到redis)一个是增量(实时更新)这里说的是增量,指的是mysql的update、insert、delate变更数据。②读取binlog后分析,利用消息队列,推送更新各台的redis缓存数据。这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性。这里可以结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到了相同的效果。

来自:redis-redis
03

为什么会出现数据一致性问题呢?

在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节。所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库。读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。

来自:redis-redis
课程
专栏
【校招VIP】Redis的8种数据类型
csdn
redis
【校招VIP】Redis数据一致性
csdn
redis
【校招VIP】Redis数据一致性问题的三种解决方案
csdn
redis
开源框架-redis-redis
3专栏
1课程
3 试题