全栈工程师修炼指南

赫赫有名的双刃剑:缓存(上)

2020-11-23  本文已影响0人  码农架构

缓存的本质

缓存,简单说就是为了节约对原始资源重复获取的开销,而将结果数据副本存放起来以供获取的方式。

缓存无处不在

缓存应用模式

Cache-Aside

数据获取策略

  1. 应用先去查看缓存是否有所需数据;
  2. 如果有,应用直接将缓存数据返回给请求方;
  3. 如果没有,应用执行原始逻辑,例如查询数据库得到结果数据;
  4. 应用将结果数据写入缓存。
image.png

数据读取的异常情形

数据更新策略 (注意顺序)

  1. 应用先更新数据库;
  2. 应用再令缓存失效。

最重要的一点是必须先更新数据库,而不是先令缓存失效,即这个顺序不能倒过来。原因在于,如果先令缓存失效,那么在数据库更新成功前,如果有另外一个请求访问了缓存,发现缓存数据库已经失效,于是就会按照数据获取策略,从数据库中使用这个已经陈旧的数值去更新缓存中的数据,这就导致这个过期的数据会长期存在于缓存中,最终导致数据不一致的严重问题。

image.png

第二个关键点是,数据库更新以后,需要令缓存失效,而不是更新缓存为数据库的最新值。为什么呢?你想一下,如果两个几乎同时发出的请求分别要更新数据库中的值为 A 和 B,如果结果是 B 的更新晚于 A,那么数据库中的最终值是 B。但是,如果在数据库更新后去更新缓存,而不是令缓存失效,那么缓存中的数据就有可能是 A,而不是 B。因为数据库虽然是“更新为 A”在“更新为 B”之前发生,但如果不做特殊的跨存储系统的事务控制,缓存的更新顺序就未必会遵从“A 先于 B”这个规则,这就会导致这个缓存中的数据会是一个长期错误的值 A。

image.png

数据更新的异常情形

Read-Through

这种情况下缓存系统彻底变成了它身后数据库的代理,二者成为了一个整体,应用的请求访问只能看到缓存的返回数据,而数据库系统对它是透明的。

image.png

数据获取策略

  1. 应用向缓存要求数据;
  2. 如果缓存中有数据,返回给应用,应用再将数据返回;
  3. 如果没有,缓存查询数据库,并将结果写入自己;
  4. 缓存将数据返回给应用。

数据读取异常的情况分析和 Cache-Aside 类似,没有数据不一致的情况发生。

Write-Through

和 Read-Through 类似,图示同上,但 Write-Through 是用来处理数据更新的场景。

数据更新策略

  1. 应用要求缓存更新数据;
  2. 如果缓存中有对应数据,先更新该数据;
  3. 缓存再更新数据库中的数据;
  4. 缓存告知应用更新完成。

这里的一个关键点是,缓存系统需要自己内部保证并发场景下,缓存更新的顺序要和数据库更新的顺序一致。

数据更新的异常情形

还有一种和 Write-Through 非常类似的数据更新模式,叫做 Write-Around。它们的区别在于 Write-Through 需要更新缓存和数据库,而 Write-Around 只更新数据库(缓存的更新完全留给读操作)。

Write-Back

对于 Write-Back 模式来说,更新操作发生的时候,数据写入缓存之后就立即返回了,而数据库的更新异步完成。这种模式在一些分布式系统中很常见。

这种方式带来的最大好处是拥有最大的请求吞吐量,并且操作非常迅速,数据库的更新甚至可以批量进行,因而拥有杰出的更新效率以及稳定的速率,这个缓存就像是一个写入的缓冲,可以平滑访问尖峰。另外,对于存在数据库短时间无法访问的问题,它也能够很好地处理。

但是它的弊端也很明显,异步更新一定会存在着不可避免的一致性问题,并且也存在着数据丢失的风险(数据写入缓存但还未入库时,如果宕机了,那么这些数据就丢失了)。

公众号:码农架构
上一篇下一篇

猜你喜欢

热点阅读