面试必问:怎么保证Redis和数据库的数据一致?

闲谈

面试官问问题时,除了问项目的某些模块的亮点技术,大部分还是热衷于对某些特殊场景(比如服务器宕机的处理方案),项目中遇到的问题怎么解决,优化策略等等。

保证redis的数据一致性其实就要想到redis怎么和数据库挂钩,因为我们一般使用redis就是做数据库的缓存。那么我们就得知道的两个操作,删除缓存更新数据库。然而这两个操作的先后顺序不同带来的效果也不同。

当然对于redis的缓存数据,我们可以更新缓存也可以删除缓存,一般来说我们都是采用删除缓存的,因为在高并发环境下,更新缓存很可能造成数据库和缓存数据不一致的问题。

解决方案

方案一: 先删除缓存,再更新数据库。
解析:

  1. 当删除缓存操作失败时,就返回错误,那么后续数据库更新操作也就不会执行了,这样保证了数据库和缓存数据是一致的。
  2. 当删除缓存成功时,更新数据库失败时,虽然数据库更新失败,但是数据库和缓存数据还是一致的,是没有影响的。
    以上说明这个解决方案很好,没有什么问题,但是加入高并发的场景中还是没有问题吗?
    问题来了,高并发中,当线程1删除缓存了,线程2同时查询发现缓存没了,那线程2就去数据库查数据写到缓存,但是同时呢,线程1更新了数据库数据。这时,缓存中的数据是线程2写入的旧数据,同时,数据库数据被线程1更新了新数据,缓存和数据库的数据是不一致的。
    所以此方案在高并发下的表现并不好,但是我们对此也是有相应解决方案的。
    高并发下,我们可以将我们的删除缓存、更新数据库、读取缓存等等操作放到队列中,这样实现串行化,保证了每个操作都是先进先出有顺序的进行。

方案二: 先更新数据库,再删除缓存。
解析:

  1. 当更新数据库成功后,删除缓存失败,这时就造成了数据库与缓存的数据不一致了。
  2. 当更新数据库失败时,就返回错误,这样就还是一致的数据。
    这种方案在高并发下表现很好,但是在某个原子操作上会出现问题,不过高并发的问题能够解决,其他的也好解决。我们解决删除缓存失败的问题时可以把要删除的数据根据key发送到消息队列中,然后去消费这些消息,得到这些key,最后不断删除操作,直到删除成功。

这种方案虽然说高并发下表现好,但也是有概率会出现问题:
当缓存刚好失效了,线程1就会查询数据库,得到旧数据,同时线程2更新数据库后把缓存删除,而同时,线程1把旧数据又写到缓存中。这样也会造成数据不一致,但是呢,触发这种问题的概率非常小,因为它需要在读缓存时刚好缓存失效,同时又并发一个写操作,实际上,写操作比读操作慢很多,还涉及到锁表,读操作又必须要在写操作前操作数据库,更新缓存也要晚于写操作,所以这种概率很小。

其实这些策略也是一种缓存模式:Cache Aside Pattern。
这种缓存模式是Facebook提供的一种缓存方案,大致内容就是告诉我们缓存操作时最好删除缓存,不会有太多问题,然后就是先更新数据库,再删除缓存的这种方案。这种方案比较稳!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值