Redis和Mysql数据库数据一致性问题

双库数据一致性问题产生的原因

Redis与Mysql双库的数据一致性问题为何会出现呢?

其实我们可以考虑这么一个业务场景:我们需要更新部分数据,我们首先更新数据库数据,然后清除Redis缓存中的数据。但是数据库更新操作成功了,然而Redis清除缓存出现异常了,这样会导致出现这么一种情况:数据库中的数据已经更新为最新数据,但是Redis缓存中的数据依旧还是老数据,这时候就会出现Redis与Mysql双库的数据一致性问题

那如果先清掉缓存中的旧数据,然后再写入新数据到数据库,最后更新缓存不就可以了么?这种方式可能出现一种问题:我们清除Redis缓存成功了,但是写入还未将新数据写入到数据库之前有读请求的发生,就会导致数据库中的旧数据再次存入Redis中,然后等到新数据写入到数据库后,一样产生了。Redis与Mysql双库的数据一致性问题

解决方案
第一种:延时双删策略(先删缓存)

双删并不是同时删除Redis和数据库,而是删除两次Redis缓存

所谓延时双删,就是先删除缓存,然后在数据库写请求后,延迟一段线程时间,再删除一次缓存,保证两次删除缓存后的双库数据是一致性的,但是再第二次删除缓存之前,也就是延迟的这段时间,还是会有可能产生双库数据不一致的问题

伪代码如下:

public void write(String key,Object data){
       redis.delKey(key);
       db.updateData(data);
       Thread.sleep(500);
       redis.delKey(key);
 }

设置缓存过期时间

从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。所有的写操作以数据库为准,只要到达缓存过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存

该方案的弊端

结合双删策略+缓存超时设置,这样最差的情况就是在超时时间内数据存在不一致,而且两次删除缓存后,再去数据库读数据,写入到Redis缓存也是增加了耗时

第二种方案:异步更新缓存(先写数据库)(基于订阅binlog的同步机制)

技术整体思路:

MySQL binlog增量订阅消费+消息队列+增量数据更新到redis

1)读Redis:热数据基本都在Redis
2)写MySQL:增删改都是操作MySQL
3)更新Redis数据:MySQ的数据操作binlog,来更新到Redis

Redis更新

数据操作主要分为两大块:一个是全量(将全部数据一次写入到redis),一个是增量(实时更新),这里说的是增量,指的是mysql的update、insert、delate变更数据

读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据

这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新

其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据一致性

主要流程如下:

1.应用程序更新数据库
2.通过canal(阿里的一款开源框架)订阅数据库的binlog
3.数据更新服务解析binlog
4.根据解析的binlog更新缓存
5.对于更新失败的,将失败的key发送到消息队列
6.缓存服务订阅消息队列,重试

Redis和Mysql数据库数据一致性问题_第1张图片

你可能感兴趣的:(Redis,redis)