Mysql和Redis数据同步策略

为什么对缓存只删除不更新

不更新缓存是防止并发更新导致的数据不一致。
所以为了降低数据不一致的概率,不应该更新缓存,而是直接将其删除,
然后等待下次发生cache miss时再把数据库中的数据同步到缓存。

先更新数据库还是先删除缓存?

有两个选择:
1. 先删除缓存,再更新数据库
2. 先更新数据库,再删除缓存

如果先删除缓存,有一个明显的逻辑错误:考虑两个并发操作,线程A删除缓存后,线程B读该数据时会发生Cache Miss,然后从数据库中读出该数据并同步到缓存中,此时线程A更新了数据库。
结果导致,缓存中是老数据,数据库中是新数据,并且之后的读操作都会直接读取缓存中的脏数据。(直到key过期被删除或者被LRU策略踢出)
如果数据库更新成功后,再删除缓存,就不会有上面这个问题。
可能是由于数据库优先,第二种方式也被称为Cache Aside Pattern

Cache Aside Pattern

cache aside在绝大多数情况下能做到数据一致性,但是在极端情况仍然存在问题。
• 首先更新数据库(A)和删除缓存(B)不是原子操作,任何在A之后B之前的读操作,都会读到redis中的旧数据。
正常情况下操作缓存的速度会很快,通常是毫秒级,脏数据存在的时间极端。
但是,对超高并发的应用可能会在意这几毫秒。
• 更新完数据库后,线程意外被kill掉(真的很不幸),由于没有删除缓存,缓存中的脏数据会一直存在。
• 线程A读数据时cache miss,从Mysql中查询到数据,还没来得及同步到redis中,
此时线程B更新了数据库并把Redis中的旧值删除。随后,线程A把之前查到的数据同步到了Redis。显然,此时redis中的是脏数据。通常数据库读操作比写操作快很多,所以除非线程A在同步redis前意外卡住了,否则发生上述情况的概率极低。虽然以上情况都有可能发生,但是发生的概率相比“先删除缓存再更新数据库”会低很多

Double-Delete

前面我们讲到先删除缓存(A)、后更新数据库(B)的方案有明显的错误,任何发生在A操作和B操作之间的并发读都会造成数据的最终不一致。
Double-Delete是一种比较笨拙的修补方案,执行过程如下:

1.delete redis cache
2.update database
3.sleep(500ms)
3.delete redis cache

也很好理解,在睡眠500ms后尝试再次删除缓存中的脏数据,它通过两次删除来尽可能做到数据的最终一致。
其实,Double-Delete在数据一致性上比Cache Aside更靠谱,但是它的代价是昂贵的,
即使,把睡眠时间缩短到100ms,对耗时敏感的应用也不会考虑这种方案。

1.写流程(更新策略)
先淘汰 cache(删除缓存);
再写 DB(更新数据库)。
2.读流程
先读 cache,如果数据命中 hit 则返回;
如果数据未命中 miss 则读 DB;
将 DB 中读取出来的数据入缓存。

什么情况下可能出现缓存和数据库不一致呢?
在这里插入图片描述
在分布式环境下,数据的读写都是并发的,上游有多个应用,通过一个服务的多个部署(为了保证可用性,一定是部署多份的),对同一个数据进行读写,在数据库层面并发的读写并不能保证完成顺序,也就是说后发出的读请求很可能先完成(读出脏数据):

  1. 发生了写请求 A,A 的第一步淘汰了 cache(如上图中的1);
  2. A 的第二步写数据库,发出修改请求(如上图中的2);
  3. 发生了读请求 B,B 的第一步读取 cache,发现 cache 中是空的(如上图中的步骤3);
  4. B 的第二步读取数据库,发出读取请求,此时 A 的第二步写数据还没开始,读出了一个脏数据放入 cache(如上图中的步骤4)。
    最终导致缓存与数据库不一致。

先更新数据库,后删除缓存(建议,使用场景最多),但是,是不是这个就不会有并发问题了?不是的,比如,一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,所以,会造成脏数据。

• 底层是在TreeMap的基础上进行封装,所以结构是红黑树。
• 因为是红黑树结构,所以不需要重写hashCode()和equals()方法来保证唯一性。
• TreeMap有的特性TreeSet都有,还在这个基础上增加了保证元素唯一性的特点。
• 可以看到构造方法是就是创建一个TreeMap,然后指向NavigableMap类型的引用。

	 private transient NavigableMap<E,Object> m;
	 TreeSet(NavigableMap<E,Object> m) {
	     this.m = m;
	 }

参考:https://www.cnblogs.com/upnote/p/13185047.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值