redis缓存一致性方案

redis缓存一致性方案

工作中经常会用redis来缓存热点数据,可以减轻底层数据库的压力,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。

一.缓存同步方式

  • 1.先删除缓存,再写库
  • 2.先写MySQL数据库,再删除Redis缓存

二.存在的问题

两种同步方式都存在问题,举例说明如下:

  • 如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。
  • 如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。

因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题。如来解决?这里给出两个解决方案,先易后难,结合业务和技术代价选择使用。

三.三种解决方案

1.延时双删策略

思路

在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。

伪代码如下:

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

具体的操作步骤如下:

  • 1.先删除缓存
  • 2.再写数据库
  • 3.休眠500毫秒
  • 4.再次删除缓存

那么,这个500毫秒怎么确定的,具体该休眠多久呢?

需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

当然这种策略还要考虑redis和数据库主从同步的耗时。最后的的写数据的休眠时间:则在读数据业务逻辑的耗时基础上,加几百ms即可。比如:休眠1秒。

该方案的弊端

当第一步删除缓存后,如果存在另一个读请求造成的缓存脏数据时。会在一段时间内数据存在不一致,而且增加了更新缓存操作的请求耗时。

2.设置缓存过期时间

思路

将缓存设置过期时间,先删除缓存,再更新数据库的数据

该方案的弊端

最坏的情况下,存在脏数据,会导致缓存过期时间内数据不一致

3.异步更新缓存(基于订阅binlog的同步机制)

思路

首先将全量数据写入到redis中,并订阅 MySQL binlog 消息,增量数据更新到redis,这里说的增量,指的是mysql的update、insert、delate变更数据。

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

这里可以结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅,而canal正是模仿了mysql的slave数据库的备份请求,使得Redis的数据更新达到了相同的效果。


引用:

1.https://zhuanlan.zhihu.com/p/95476839

猜你喜欢

转载自blog.csdn.net/godloveleo9527/article/details/108628079