后端工程师的高阶面经
邓明
前 Shopee 高级工程师,Beego PMC
6888 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 50 讲
后端工程师的高阶面经
15
15
1.0x
00:00/00:00
登录|注册

34|缓存一致性问题:高并发服务如何保证缓存一致性?

你好,我是大明。今天我们来聊一个面试缓存必然会涉及的一个问题:怎么保证数据一致性?
上一节课我详细分析了各个缓存模式,你会发现这些缓存模式要么存在数据丢失的可能,要么在某一段时间内总是会不一致。那么有没有能够彻底解决缓存一致性的方案呢?
这节课我就带你分析各种可行的解决方案,并且告诉你这些方案在保障数据一致性上,究竟能够做到什么地步。
为了方便你理解后面的内容,我们先来看 double-check 模式。

double-check 模式

double-check 是并发里为了兼顾并发安全和性能经常采用的一种代码模式。它的基本思路可以总结为检查、加锁、检查,所以也叫做 double-check。double-check 经常用在使用读写锁的场景。这里我用伪代码来描述它的基本思路。
func doubleCheck() {
rlock() // 加读锁
if !checkSomething() {
// 执行一些动作
return
}
runlock() // 释放读锁
lock()
if !checkSomething() {
// 执行一些动作
return
}
// 执行另外一些动作
lock()
}
比如,先加读锁检测数据是否存在,如果存在就直接返回,否则就释放读锁,加写锁,再次检查数据是否存在,存在就直接返回,不存在就根据业务计算数据并返回。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了高并发服务中缓存一致性的重要性及解决方案。首先介绍了 double-check 模式及其变种,以及数据不一致的根源和解决方案,如消息队列和版本号的方案。文章还探讨了多级缓存架构下的数据一致性问题,强调了更新数据库优先、本地缓存次之、最后更新 Redis 的顺序。此外,还介绍了一致性哈希和缓存的方案,以及分布式锁方案。在讨论中,强调了负载均衡算法和 singleflight 模式的重要性,以及在节点上线或下线时的处理方法。总体而言,本文内容丰富,涵盖了缓存一致性的多个方面,对于需要深入了解缓存一致性问题的读者具有很高的参考价值。文章内容涉及了 double-check 模式、数据不一致的根源和解决方案、多级缓存架构下的数据一致性问题、一致性哈希和缓存的方案、分布式锁方案等多个方面,为读者提供了全面的技术视角和解决思路。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端工程师的高阶面经》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(9)

  • 最新
  • 精选
  • 木木夕
    现在面试都这样用一些在生产不切实际的方案吗?Cache Aside 就能满足百分之99的场景了。你们真的会在项目中这样应用嘛?

    作者回复: 我从实践和面试上来讲这个问题。 实践中用不用?答案是基本不用,你说 99% 的比例我也差不多赞同。但是你说我有没有用过,我确实用过,各种骚操作。 面试中呢?答案就更加简单了,Cache Aside 大家都会,我凭什么给你 offer 呢? 我个人认为,即便公司用不着,你自己也应该尝试一下,毕竟还是那句话,简单的东西大家都会,你凭什么在面试中拿到 offer 呢?

    2023-09-07归属地:广东
    2
    6
  • stevensafin
    实际有应用吗

    作者回复: 嘿嘿,都搞过。

    2023-09-06归属地:广东
    1
  • penbox
    1. 分布式方案的思路二里面,是先提交事务再释放分布式锁,顺序能反过来吗? 不可以。释放分布式锁之后,读请求就能直接从数据库加载数据了,此时更新事务可能还没有提交,读到的就会是旧的数据。 2. 有一种使用分布式锁的方案是先加分布式锁,再执行本地事务并提交,最后删除缓存,释放分布式锁。这种方案有什么缺点?有没有可能出现数据不一致? 分布式锁的占用时间也会很长,还不能保证一致性。 在失败的情况下:如果事务提交失败,不会删除缓存,数据还是一致的;如果事务提交成功,但是缓存删除失败了,那么数据就不一致了。

    作者回复: 赞!

    2023-09-06归属地:四川
    1
  • 天天有吃的
    在有分布式锁的情况下,seata tcc给redis值补回去也可以吧

    作者回复: 这个我倒是没深入研究过,所以不太了解。

    2024-03-03归属地:福建
  • fd
    怎么通知到所有的本地缓存都更新呢?

    作者回复: 1. RPC 中的广播调用 2. 借助某些配置中心,大家都监听 key,key 一旦变化,大家就重新加载缓存。 3. 订阅 Kafka,每个节点都是一个独立的消费者组,监听到消息就重新加载。

    2024-02-21归属地:广东
    2
  • 大将军Leo。。
    老师,一致性哈希 + Redis + 本地缓存这个方案我有个细节问题问下: 本地缓存的更新问题,文章里面提到,如果更新这个操作也是用户通过网关(一致性哈希)触发这种我们可以在一个pod里面解决。 但是如果这个更新操作不是用户触发,可能是通过其他系统内部rpc回调的没走网关,这种怎么处理?如果使用binglog订阅再加广播,但是这个消费这里怎么处理、需要和网关这里联动(因为节点数量加减很可能网关路由变更)?

    作者回复: 你是为了更新数据的时候同步更新本地缓存?这种情况下没有特别好的做法。一种做法是虽然你不经过网关,但是你做客户端负载均衡的时候按照同样的算法来筛选节点。 你的场景没有说清楚,所以我也不了解你们的binlog 和广播是怎么一回事。不过如果有人能够绕过负载均衡,那么我不是很建议你实践中用这个方案。

    2024-01-18归属地:广东
    2
  • 好运来
    回查请求加分布式锁图中 右边加分布式锁 -》读数据a=2 -》更新缓存a=1 这里是不是错了,应该是 右边加分布式锁 -》读数据a=2 -》更新缓存a=2 这样吧?

    作者回复: 嗯嗯,感谢勘误。

    2023-09-13归属地:广东
  • peter
    “同一个 key 的请求都落在同一个节点上,依旧存在并发更新的问题”,既然是同一个key的请求,为什么还会有并发问题?

    作者回复: 没有 singleflight 的时候,你多个线程更新数据库和缓存这种场景。

    2023-09-06归属地:河南
    2
  • on
    这一讲中的读加锁,double check,在并发环境中基本不可取,会堵并发的
    2024-03-20归属地:上海
收起评论
显示
设置
留言
9
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部