前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >缓存同步策略之如何解决缓存最终一致性问题

缓存同步策略之如何解决缓存最终一致性问题

原创
作者头像
小草飞上天
发布2025-01-02 11:11:59
发布2025-01-02 11:11:59
1100
举报
文章被收录于专栏:java学习

引言

在高并发访问的情况下,很可能会导致数据不一致,那<如何保证数据的一致性>这个问题已经属于老生长谈的问题了。

是先更新数据库,再更新缓存 ?

还是先更新缓存,再更新数据库?

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

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

什么是延迟双删?

什么是双检加锁策略?

等等。

对于一个常规系统来说,如何保证其数据一致性是不得不解决的问题。

我们按照上面列出的疑问流程,一个一个说一下缓存的问题及如何解决。

先更新数据库,再更新缓存 ?

首先先说结论:这种缓存策略是有问题的

我们以订单系统为例。可以看一下:

  1. 先更新数据库的商品库存,商品库存为 10000 ,更新为 999
  2. 数据库更新成功。开始更新缓存
  3. 假设缓存更新失败。这时候:缓存是 10000 ,但数据库已经是 999这种情况下

上面这种情况,会让数据库和缓存里面数据不一致。读取redis的脏数据。

先更新缓存,再更新数据库 ?

首先先说结论:这种缓存策略也是有问题的

我们以订单系统为例。可以看一下:多个请求的情况,A和B代表2个不同请求

  1. A请求先更新缓存的商品库存,商品库存为 10000 ,更新为 999
  2. B请求先更新缓存的商品库存,商品库存为 999,更新为 998
  3. 这时候在业务上,由于某些资源问题。导致A请求服务卡顿。导致B请求优先执行
  4. B请求更新数据库的商品库存,数据库的商品库存为 10000,更新为 998
  5. A请求更新数据库的商品库存。数据库的商品库存为 998,更新为 999

上面这种情况,会让数据库和缓存里面数据不一致。

请注意:这种是肯定不行的。因为我们应用一般是将数据库做为最终的准确数据。而不是缓存。

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

首先先说结论:这种缓存策略也是有问题的

我们以订单系统为例。可以看一下:多个请求的情况,A和B代表2个不同请求

  1. A请求先删除缓存。此时,商品库存为 10000 ,无缓存。
  2. B请求来读取商品库存。此时,重建缓存,商品库存为 10000,缓存库存为 10000
  3. A请求更新数据库的商品库存,商品库存为 10000 ,更新为 999

上面这种情况,缓存库存还是为10000,导致数据库和缓存里面数据不一致。

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

首先说结论: 这种情况可以接受。但还需要有其他补偿措施,防止删除缓存失败等情况。

这种情况大概率是可以接受的,但也会存在部分问题。比如:假如缓存删除失败或者来不及,导致请求再次访问redis时缓存命中,读取到的是缓存旧值。

总体来说,上面四种方案都不是特别完美。能接受的也就是先更新数据库。再删除缓存这种方案。但对于好的系统来说,这种方案也是不可接受的。所以基于此。业界也提出了解决方案:延迟双删、异步同步等

延迟双删

延时双删策略的实现步骤如下:

  1. 删除Redis缓存
  2. 更新数据库
  3. 延迟一段时间后再次删除Redis缓存。

这种策略的关键在于延迟删除的时间设置。这个时间必须大于将数据库旧数据写入Redis的时间,通常是几百毫秒到几秒不等,具体时间取决于业务需求。

但基于开发者来说,这个基于业务需求得到的延迟删除的具体时间,一般情况下开发者很难评估。

但对于一般的项目来说,其实也足够。毕竟要触发异常情况的概率挺低。

通过数据库binlog进行异步缓存同步

所谓binlog的异步缓存同步。实际也是延迟双删的扩展。他只是将延迟删除缓存变更为了异步通过数据库binlog同步来删除缓存。这样就很好的处理了延迟双删中删除时间设置不太好解决。

核心原理:在数据写入 MySQL 数据库后,通过Canal读取 MySQLbinlog(二进制日志)日志来获取数据的相关操作信息并同步给客户端,客户端根据需求异步地删除对应的缓存数据。这样可以在缓存删除失败或者延迟时,通过读取 binlog 重新进行缓存删除操作。

关于Canal相关的文章可以查看:Canal 实战 : 异步实践缓存最终一致性

这里将操作的数据写入消息队列的核心原因是:防止一些特殊原因导致删除缓存失败,起一个重试的机制。

其次。对于Canal同步binlog日志,这里也是需要使用消息队列来消费相关的日志的。需要注意。

总结

总体来说,缓存是不可能实时的一致性的。我们只能以 最终一致性目标 来进行业务梳理。

大部分业务情况下。我们采用的同步策略都是:延迟双删 + 异步同步进行缓存的 最终一致性处理。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 先更新数据库,再更新缓存 ?
  • 先更新缓存,再更新数据库 ?
  • 还是先删除缓存。再更新数据库?
  • 还是先更新数据库。再删除缓存?
  • 延迟双删
  • 通过数据库binlog进行异步缓存同步
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档