(扩展二)redis和数据库一致性

不管是先写数据库再删除缓存,还是先删除缓存再写数据库,都会出现缓存不一致情况:

  1. 如果先删除缓存,还没有来得及写mysql,这时候另外一个线程读取数据发现缓存为空,就读取数据库旧数据并更新缓存。此时写入mysql后缓存数据为脏数据。
  2. 先写数据库,再删除缓存之前写库的线程挂了没有及时更新缓存,也会出现不一致情况

 

严格要求缓存+数据库必须一致性

唯一方案:读请求和写请求串行化。根据唯一标识路由之后,将请求串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况

缺点:串行化后吞吐量大幅度降低

致命缺点:内存队列读写串行化只能保证单机情况,集群需要保证集群串行化。可考虑分布式锁,利用zk的临时顺序节点进行集群服务排队!!

最经典的缓存+数据库读写的模式

1、Cache Aside Pattern

(1)读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取出数据后放入缓存,同时返回响应

(2)更新的时候,先删除缓存,然后再更新数据库

2、为什么是删除缓存,而不是更新缓存呢?

原因一:很简单,很多时候,复杂点的缓存的场景,因为缓存有的时候,不简单是数据库中直接取出来的值,需要计算

原因二:数据频繁修改,但是查询不频繁。即使每次及时更新缓存也没有人去查询

重点来了!!!!!!!!!

缓存不一致解决方案

方案一:延时双删+设置超时

操作步骤

  1. 先删除缓存
  2. 再写数据库
  3. 休眠500毫秒(休眠时间要看具体的业务。考虑到redis主从延迟)
  4. 再次删除缓存

备注:在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。这样最差的情况是在超时时间内存在不一致,当然这种情况极其少见,可能的原因就是服务宕机。此种情况可以满足绝大多数需求。 当然这种策略要考虑redis和数据库主从同步的耗时,所以在第二次删除前最好休眠一定时间,比如500毫秒,这样毫无疑问又增加了写请求的耗时

参考:https://blog.csdn.net/belongtocode/article/details/104355460

方案二:异步更新缓存(基于订阅binlog的同步机制)

优点:业务代码侵入少,可保证最终一致性

猜你喜欢

转载自blog.csdn.net/lss446937072/article/details/109609040