前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你是如何更新缓存的?看懂这篇缓存读写策略

你是如何更新缓存的?看懂这篇缓存读写策略

作者头像
JavaEdge
发布2022-11-30 15:56:15
8910
发布2022-11-30 15:56:15
举报
文章被收录于专栏:JavaEdgeJavaEdge

也许你会觉得缓存读写很简单:

  • 先读缓存,缓存不命中就查DB,查到了就回种缓存
  • 先删缓存,再更新DB,而后续操作会把数据再装载到缓存 这是错误的。最简单的两个并发操作:更新&查询。 更新操作删除缓存后,查询操作没有命中缓存,先把老数据读出来后放到缓存,然后更新操作更新了数据库。于是,缓存中的数据还是老数据,导致缓存中的数据是脏的,而且还一直这样脏下去。

针对不同的业务场景,实际选用的缓存的读写策略也不同。为方便讨论,这里假定更新数据库、缓存都成功。

1 Cache Aside(旁路缓存)

最常用的模式:

  • 失效 应用先从cache取数据,没有得到,则从DB取数据,成功后,放入cache
  • 命中 应用程序从cache中取数据,取到后返回
  • 更新 先把数据存到DB,成功后,再让缓存失效
Cache-Aside-Design-Pattern-Flow-Diagram
Cache-Aside-Design-Pattern-Flow-Diagram
Updating Data using the Cache-Aside Pattern - Flow Diagram
Updating Data using the Cache-Aside Pattern - Flow Diagram

注意,是先更新DB,成功后,让缓存失效。

一个查询操作,一个更新操作的并发 首先,没有了删除cache数据的操作,而是先更新数据库中的数据,此时,缓存依然有效,所以,并发的查询操作拿的是没有更新的数据,但是,更新操作马上让缓存的失效了,后续的查询操作再把数据从数据库中拉出来。而不会像文章开头的那个逻辑产生的问题,后续的查询操作一直都在取老的数据。

这是标准的design pattern,包括Facebook的论文《Scaling Memcache at Facebook》也使用了这个策略。为什么不是写DB后更新缓存?可以看一下Quora上的这个问答《Why does Facebook use delete to remove the key-value pair in Memcached instead of updating the Memcached during write request to the backend?》,主要是怕两个并发的写操作导致脏数据。

那Cache Aside有并发问题吗? 有。比如,一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,所以,会造成脏数据。

这个情形理论上会出现,不过,实际上出现的概率可能非常低,因为需要发生在读缓存时缓存失效,而且并发着有一个写操作。 而实际上数据库的写操作会比读操作慢得多,而且还要锁表,而读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存,所有的这些条件都具备的概率基本并不大

这也就是Quora上的那个答案里说的,要么通过2PC或是Paxos协议保证一致性,要么就是拼命的降低并发时脏数据的概率,而Facebook使用了这个降低概率的玩法,因为2PC太慢,而Paxos太复杂。当然,最好还是为缓存设置上过期时间。

2 Read/Write Through Pattern

上面的Cache Aside,应用代码需要维护两个数据存储,一个是缓存,一个是数据库,应用程序比较啰嗦。 而Read/Write Through是把更新数据库的操作由缓存自己代理,所以,对于应用层来说,就简单很多。 可理解为,应用认为后端就是一个单一的存储,而存储自己维护自己的Cache。

2.1 Read Through

Read Through 就是在查询操作中更新缓存,也就是说,当缓存失效的时候(过期或LRU换出)

  • Cache Aside是由调用方负责把数据加载入缓存
  • Read Through则用缓存服务自己来加载,从而对应用方是透明的

2.2 Write Through

和Read Through相仿,不过是在更新数据时发生 当有数据更新时

  • 如果没有命中缓存,直接更新数据库,然后返回
  • 如果命中了缓存,则更新缓存,然后再由Cache自己更新数据库(这是一个同步操作)

下图中的Memory可以理解为就是我们例子里的数据库

A write-through cache with no-write allocation
A write-through cache with no-write allocation

3 Write Behind(异步写回)

又叫 Write Back。在更新数据时,只更新缓存,不更新DB,而我们的缓存会异步批量更新DB

优点

  • 让数据的I/O操作飞快无比(因为直接操作内存嘛 )
  • 因为异步,write back还可以合并对同一个数据的多次操作,所以性能的提高是相当可观

缺点

数据不是强一致性的,而且可能会丢失(我们知道Unix/Linux非正常关机会导致数据丢失,就是因为这个事)。

另外,Write Back实现逻辑比较复杂,因为他需要track哪些数据是被更新的,需要刷到持久层。 os的write back会在仅当这个cache需要失效时,才会被真正持久化,比如,内存不够了,或是进程退出了等情况,这又叫lazy write。

比如在向磁盘中写数据时采用的也是这种策略。无论是:

  • os层面的 Page Cache
  • 日志的异步刷盘
  • 消息队列中消息的异步写入磁盘

大多采用了这种策略。因为这个策略在性能优势明显,直接写内存,避免了直接写磁盘造成的随机写。

  • A write-back cache with write allocation

参考

  • https://coolshell.cn/articles/17416.html
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-03-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 Cache Aside(旁路缓存)
  • 2 Read/Write Through Pattern
    • 2.1 Read Through
      • 2.2 Write Through
      • 3 Write Behind(异步写回)
        • 优点
          • 缺点
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档