当前位置: 首页 > article >正文

数据库和缓存的数据一致性 -20241124

问题描述

  • 一致性
    • 缓存中有数据,缓存的数据值=数据库中的值
    • 缓存中本没有数据,数据库中的值=最新值(有请求查询数据库时,会将数据写入缓存,则变为上面的“一致”状态)
  • “数据不一致”:
    • 缓存的数据值≠数据库中的值;
    • 缓存或者数据库中存在旧值,导致其他线程读到旧数据。

应对策略

  • 把缓存分成读写缓存和只读缓存。
    • 只读缓存:只在缓存进行数据查找,即使用“更新数据库+删除缓存”策略。
      • 新增数据时,直接写入数据库;
      • 更新(修改/删除)数据时,先删除缓存。
      • 后续访问这些增删改的数据时,会发生缓存缺失,进而查询数据库,更新缓存
      • 文中提到无并发情况下,若步骤二失败会有一致性问题。
        • 可以采用消息队列,异步重试。(多次失败后通知业务层)
        • 也可采用binlog变更日志,根据日志更新/删除缓存
      • 并发条件下
        • 先删除缓存,再更新数据库(其他线程在缓存为空时访问数据库获得旧值,顺便将缓存更新了,造成缓存中的值在A线程完成更新数据库后也不再更新)
          • 设置缓存过期时间。淘汰缓存失败时,过期后,读请求从db中获取数据,并更新缓存。(?删除缓存可能会失败,设置超时时间就保证能成功了?)
          • 延迟双删:更新完数据库后,等待一段时间(使确保其他线程能读到修改后的值),再删除缓存
        • 先更新数据库,再删除缓存(线程B读到旧值,?感觉问题不大;若有从库,会尝试去从库拿?,由于主从库的延迟,造成缓存中保存的是从库中的旧值)
          • 延迟消息:发送删除缓存的消息到队列,延迟处理。如有必要,考虑主从数据库延迟
          • 通过数据库的binlog来异步删除缓存
          • 先更新数据库再删除缓存,有可能导致请求因缓存缺失而访问数据库,给数据库带来压力,也就是缓存穿透的问题。针对缓存穿透问题,可以用缓存空结果、布隆过滤器进行解决
          • 加锁:更新数据时,加写锁;查询数据时,加读锁
    • 读写缓存:需要在缓存中对数据进行增删改查,即使用“更新数据库+更新缓存”策略
      • 同步直写:使用事务,保证缓存和数据更新的原子性,并进行失败重试
      • 异步回写:写缓存时不同步写数据库,等到数据从缓存中淘汰时,再写回数据库
    • 重点考虑更新数据库和缓存的顺序,读写还是读读
      • 对于读写场景,延迟消息比较,发现不一致后,做业务补偿(加延迟时间?)
      • 对于,写写场景,配合分布式锁处理。对于同一资源的操作,需要获取分布式锁,未获得锁的放在队列中。

总结

  • 数据库和缓存存在不一致性,部分原因是因为数据库和缓存是独立的两部分。从设计上可能做了适配,但是总归有配合问题。如果数据库本身在设计上就考虑设计高并发缓存,我们在使用时就不用考虑一致性问题或者性能问题。
    • 如人为设置一个等待时间,在数据库应该能完成数据更新的时,进行缓存的删除。如果数据库与缓存是一体的,可能在内部就能完成,数据库完成删除后通知缓存更新。这样效率肯定比外界干预的两部效率要高
  • 性能和准确性的取舍在因场景而异,我们只能采用该架构下我们认知中,在该场景下,在有限的时间内能够完成的最优方案。

参考:https://cloud.tencent.com/developer/article/1888803


http://www.kler.cn/a/413698.html

相关文章:

  • 读《Effective Java》笔记 - 条目11
  • Git上传本地项目到远程仓库(gitee/github)
  • 【鸿蒙】鸿蒙开发过程中this指向问题
  • Python语法基础(三)
  • 数据结构C语言描述5(图文结合)--广义表讲解与实现
  • android studio Terminal控制台命令打包 apk
  • Excel如何设置超出单元格的内容不显示?
  • Unity图形学之折射
  • 【Qt--从入门到精通】什么是Qt?如何使用Qt创建一个简单的项目
  • SpringBoot+MyBatis+lombok进行数据库操作的小案例
  • React Native 性能调试指南
  • 时钟使能、
  • 安装QT6.8(MSVC MinGW)+QT webengine+QT5.15.2
  • git 命令查询
  • 渗透的本质是信息收集——一点思考
  • componentReceivePropsreact class生命周期
  • 【vue3实现微信小程序】从轮播图到公告栏的前端开发之旅
  • 小R的二叉树探险 | 模拟
  • Windows 11 搭建 Docker 桌面版详细教程
  • 读书笔记_《创华为.任正非传》_精华书摘
  • 241125学习日志——[CSDIY] [ByteDance] 后端训练营 [16]
  • 【通俗理解】Adaptive Gradient Algorithm(自适应梯度算法)——从梯度下降到优化器选择
  • 《Gin 框架中的表单处理与数据绑定》
  • 跳表(Skip List)
  • TCP网络套接字
  • Python中3中并发对比