写点什么

Redis 缓存应用—旁路缓存和数据一致性

作者:javaadu
  • 2022 年 3 月 20 日
  • 本文字数:1396 字

    阅读完需:约 5 分钟

Redis缓存应用—旁路缓存和数据一致性

缓存的作用

在大型软件系统的构建中,分层是一种很好的设计思路,我们通过抽象思维,将同一个抽象层次的概念放在同一层次交互,上层以来下层的接口,下层对上层隐藏复杂的实现细节。操作系统、rpc 框架、大型应用系统都有类似的分层的概念在里面。


操作系统中的缓存应用

不同的存储介质的存储容量和存取速度是各不相同的,在操作系统的存储架构中,从 CPU 寄存器到外部磁盘存储,存取速度逐步降低,但是存储容量逐步上升。在这个体系中,高速缓存是内存在 CPU 侧的缓存,磁盘缓存是磁盘在内存侧的缓存。



分布式系统中的缓存架构

同样的思想,也用在了电商、游戏、云计算等分布式系统中,对于那些高并发、高性能读取要求的业务功能,我们会将这些数据(商品、属性等等)放到不同层级的缓存中。下面这个体系中,进程内存作为分布式缓存的缓存,分布式缓存作为 MySQL 数据源的缓存。



缓存的设计模式

一般来说,如果没有必要,我们是不会引入缓存的,引入缓存之后,我们就需要考虑缓存的更新模式,以及缓存的数据一致性问题。更新缓存的的设计有四种:Cache aside, Read through, Write through, Write behind caching,我们一一看下。

Cache Aside(旁路缓存)

如果缓存存储器没有提供原生的写直通或读直通能力,并且我们也不清楚需要将哪些数据存入缓存,希望能够根据应用的需要(时间或空间局部性)来缓存数据,则比较适合用这种模式。整个业务逻辑没有缓存也可以完成,无非就是效率低一些,旁路缓存的作用就是用来提效。

  • 读取:如果缓存命中则直接返回,如果没有则从数据库中读取,并且将读取的数据写回缓存。

  • 更新:先更新数据库,再删除缓存。



旁路缓存中的缓存和数据源是两个不同的实体,因此存在一致性问题,为了降低数据不一致的概率,我们讨论下集中更新数据时候的模式:

  • “先更新数据库,再更新缓存”是有问题的,在并发写的情况下会导致缓存中存在脏数据,缓存和 DB 存在不一致的数据



  • “先更新缓存,再更新数据库”也是有问题的,在并发写情况下可能会导致缓存中存在脏数据,缓存和 DB 存在不一致的数据



  • “先更新数据库,再删除缓存”是不是就没问题呢?理论上,可能出现一种情况,A 线程读取缓存未命中,然后去读数据库,这时候读到老的数据,同时一个 B 线程去更新数据库,更新完后还要将缓存失效,然后 A 线程读到老的数据并将其放入缓存,造成脏数据,但在实际中这种情况的概率极低——要求读取数据库的操作慢于写数据的操作,因此,标准的做法就是“先更新数据库,再失效缓存”,如果担心操作缓存失败,则可以将缓存设计一个过期时间,或者进行同步重试或异步重试。



Read/Write Through(读/写直通)

在上面的 Cache Aside 更新模式中,应用代码需要维护两个数据存储,一个是缓存(Cache),一个是数据库(Repository)。而在 Read/Write Through 更新模式中,应用程序只需要维护缓存,数据库的维护工作由缓存代理了。



Write Behind Cache

Write Behind Caching 更新模式和 Read/Write Through 更新模式类似,区别是 Write Behind Caching 更新模式的数据持久化操作是异步的,但是 Read/Write Through 更新模式的数据持久化操作是同步的。Linux 中的文件系统里的 Page Cache 算法,使用的就是 Write Behind Cache 模式。

  • 优点:直接操作内存速度快,多次操作可以合并持久化到数据库。

  • 缺点:数据可能会丢失,例如系统断电等。



参考资料

  1. https://coolshell.cn/articles/17416.html

  2. https://mp.weixin.qq.com/s/4W7vmICGx6a_WX701zxgPQ


知识卡片



发布于: 4 小时前阅读数: 8
用户头像

javaadu

关注

功不唐捐 2017.09.10 加入

蚂蚁金服后端开发者,擅长java、spring、spring boot、jvm、分布式架构、软件设计等领域的技术分享,对于风控业务有一定的了解

评论

发布
暂无评论
Redis缓存应用—旁路缓存和数据一致性_redis_javaadu_InfoQ写作平台