Redis和数据库如何保证数据一致性

一.问题简

在并发低、用户少的情况下,每次查询都能去Mysql查询数据返回,但在高并发情况下,每一个读请求都到Mysql去查询会导致数据库压力太大。

所以一般会使用Redis做一个缓冲,减轻数据库的压力:

正常情况下,使用Redis缓存数据流程如下:

正常的读请求该模式不会有问题,但是如果数据库信息有改动,那么数据库和Redis的数据一致性如何保证?

按我们常规的逻辑,数据库修改后去删除Redis的key即可。

其实不管是先删Redis再修改库,还是先修改库再删Redis都会有问题,因为读线程和写线程是并发的,无法保证其执行顺序。

1.如果先删Redis缓存,再写库。在删除Redis缓存后,写线程还没来得及修改数据,这时读线程发现缓存为空,则取读取了脏数据。

2.如果先修改数据,在删Redis缓存。在修改数据后如果线程宕机,那么Redis缓存删除失败,也会出现脏数据。

二.延时双删策略+设置缓存过期时间

所谓双删策略,就是在更新库的前后都进行Redis缓存的删除,但是更新后的删除时延时删除,伪代码如下:

public void update(){
  //1.删除Redis缓存
  redisTemplate.delete(key);
  //2.更新数据库
  mysqlConnection.update();
  //3.延时删除
  Thread.sleep(200);
  redisTemplate.delete(key);
}

 等待的时间如何确定

等待的时间为读线程读取数据的一个耗时,包括Redis主从同步,网络耗时等。

为什么要使用延时删除

为了防止在更新数据的过程中有读线程进来缓存数据,所以更新后估算一个时间再删除Redis缓存。

为什么要设置缓存过期时间

设置缓存时间是保证数据一致性的最终解决方案,因为在最坏情况下,脏数据的时间最多为设置的过期时间。过期后读线程会到数据库读取新数据。

该方案有什么弊端

1. 最坏情况是在一个过期时间内会存在脏数据。

2. 因为有延时,所以增加的写线程的执行时间。

三.基于订阅binglog的同步机制

后续完善

posted @ 2021-12-13 22:19  EchoLv  阅读(4494)  评论(0编辑  收藏  举报