解决 Redis 与 MySQL 数据一致性问题

本文探讨了数据库与缓存一致性问题,特别是Redis作为缓存时的挑战。文章介绍了Cache-Aside、Read-Through、Write-Through和Write-Behind等缓存策略,分析了它们在保证数据一致性和性能方面的影响。重点讨论了旁路缓存策略下的四种更新顺序,以及可能引发的数据不一致情况。提出了缓存延时双删、删除缓存重试机制和读取binlog异步删除等一致性解决方案,总结了缓存策略的最佳实践和在追求最终一致性时的权衡。
摘要由CSDN通过智能技术生成

1. 什么是数据库与缓存一致性

数据一致性指的是:

  • 缓存中存有数据,缓存的数据值 = 数据库中的值;
  • 缓存中没有该数据,数据库中的值 = 最新值。

反推缓存与数据库不一致:

  • 缓存的数据值 ≠ 数据库中的值;
  • 缓存或者数据库存在旧的数据,导致线程读取到旧数据。
为何会出现数据一致性问题呢?

把 Redis 作为缓存的时候,当数据发生改变我们需要双写来保证缓存与数据库的数据一致。

数据库跟缓存,毕竟是两套系统,如果要保证强一致性,势必要引入 2PCPaxos 等分布式一致性协议,或者分布式锁等等,这个在实现上是有难度的,而且一定会对性能有影响。

如果真的对数据的一致性要求这么高,那引入缓存是否真的有必要呢?

2. 缓存的使用策略

在使用缓存时,通常有以下几种缓存使用策略用于提升系统性能:

  • Cache-Aside Pattern(旁路缓存,业务系统常用)
  • Read-Through Pattern
  • Write-Through Pattern
  • Write-Behind Pattern

2.1 Cache-Aside (旁路缓存)

所谓「旁路缓存」,就是读取缓存、读取数据库和更新缓存的操作都在应用系统来完成业务系统最常用的缓存策略

2.1.1 读取数据

读取数据逻辑如下:

  1. 当应用程序需要从数据库读取数据时,先检查缓存数据是否命中。
  2. 如果缓存未命中,则查询数据库获取数据,同时将数据写到缓存中,以便后续读取相同数据会命中缓存,最后再把数据返回给调用者。
  3. 如果缓存命中,直接返回。

时序图如下:

优点

  • 缓存中仅包含应用程序实际请求的数据,有助于保持缓存大小的成本效益。
  • 实现简单,并且能获得性能提升。

实现的伪代码如下:

String cacheKey = "公众号:码哥字节";
String cacheValue = redisCache.get(cacheKey);
//缓存命中
if (cacheValue != null) {
  return cacheValue;
} else {
  //缓存缺失, 从数据库获取数据
  cacheValue = getDataFromDB();
  // 将数据写到缓存中
  redisCache.put(cacheValue)
}

缺点

由于数据仅在缓存未命中后才加载到缓存中,因此初次调用的数据请求响应时间会增加一些开销,因为需要额外的缓存填充和数据库查询耗时。

2.1.2 更新数据

使用 cache-aside 模式写数据时,如下流程。

  1. 写数据到数据库;
  2. 将缓存中的数据失效或者更新缓存数据;

使用 cache-aside 时,最常见的写入策略是直接将数据写入数据库,但是缓存可能会与数据库不一致。

我们应该给缓存设置一个过期时间,这个是保证最终一致性的解决方案。

如果过期时间太短,应用程序会不断地从数据库中查询数据。同样,如果过期时间过长,并且更新时没有使缓存失效,缓存的数据很可能是脏数据。

最常用的方式是删除缓存使缓存数据失效

为啥不是更新缓存呢?

性能问题

当缓存的更新成本很高,需要访问多张表联合计算,建议直接删除缓存,而不是更新缓存数据来保证一致性。

安全问题

在高并发场景

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值