写点什么

架构误区系列 7:删除 + 更新的缓存刷新机制

作者:agnostic
  • 2022-11-27
    上海
  • 本文字数:818 字

    阅读完需:约 3 分钟

缓存是我们在架构中比较常用的一种基础组件,目的是为了提升后端的查询效率,控制对于存储的访问量保证数据库等基础设施的稳定。

但是,在缓存的使用上,部分架构师过于强调数据库和缓存数据一致性,做了很多多余的设计,不但加大了软件的复杂度,在一些特殊场景下反而导致了一些非预期异常的出现。


最近在 CR 中发现,开发的同学为了提升数据库和缓存的一致性,设计了一个删除+更新的缓存刷新逻辑:

  • 修改数据的进程在修改完数据后,删除缓存。

  • 数据读取方查询缓存未命中时,刷新缓存。

仔细琢磨一下这个设计,其实在刷新频繁的场景下是存在 bug 的。我们考虑如下场景:

  • 更新者 A 更新数据,删除缓存。

  • 更新者 B 更新数据,删除缓存。

  • 读取放 C 在两者之间读取数据。

在极端场景下,C 在 A 删除数据之后读取,发现缓存为空,开始启动缓存刷新机制。读取数据库拿到 A 更新后的数据。在写入缓存之前,B 更新了数据并删除了缓存。这个时候,load 到缓存中的数据是 A 的版本而安非 B 的版本。在缓存失效前,缓存中都是“脏数据”。而在这种删除+更新的逻辑下,一般缓存的失效时间会设置的比较大。


这种删除+更新的设计,其实是一个典型的过度设计。

首先,我们需要充分意识到数据库和缓存是两个组件,除非在两者之间开启分布式事务,否则保证两者的强一致性是不可能的。在数据库和缓存之间开启分布式事务做数据同步,最简单的方式就是在写入数据的售后开启分布式锁,这种方式降低了数据更新的并发度,损失基本大于收益。


数据库和缓存之间,最可行的就是保证最终一致性,或者线形一致性。数据库数据修改最终能同步到缓存,缓存不会将新数据更新成老数据,基本上就可以达到两者一致性的要求。


一种方式的写入方更新缓存。写入的同时用注册缓存更新任务。缓存更新时间判断缓存版本,避免乱序更新。

另一种方式是缓存过期+读方更新。读取方在没有数据的情况下去更新缓存,缓存在一定时期后过期。这种方式需要比较短的过期时间,否则在过期前缓存是不会被更新的。


不管哪种方式,都由一方对缓存的刷新负责。


发布于: 刚刚阅读数: 7
用户头像

agnostic

关注

常识、KISS、高可用、合规架构、架构治理 2019-02-14 加入

二十年架构经验,互联网金融专业架构师。Open Group Master Certified Architect

评论

发布
暂无评论
架构误区系列7:删除+更新的缓存刷新机制_缓存_agnostic_InfoQ写作社区